tag:blogger.com,1999:blog-61092254947074881362024-02-19T09:03:38.652-08:00My Scripts RepositoryElkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.comBlogger60125tag:blogger.com,1999:blog-6109225494707488136.post-89540634293304378252022-09-30T21:18:00.000-07:002022-09-30T21:19:35.856-07:00VRA ABX Action to set Deployment Lease<p> Running vRealize Automation (VRA), I wanted to create a new catalog item in Service Broker that would basically self-destruct after a certain time. My intent is to allow our Windows engineers to quickly spin up a new machine in AWS with a lease applied to it. </p><p>I could find a catalog template setting that allowed me to configure this, so I found that I could do this via a REST call to the VRA. So I decided to work on creating an extensibility action using Powershell. </p><p>Note, once a lease is set, I don't think it's possible to remove the lease. </p><p>Pre-requisites:</p><p></p><ul style="text-align: left;"><li><a href="https://docs.vmware.com/en/vRealize-Automation/services/Using-and-Managing-Cloud-Assembly/GUID-3F363A84-4F4F-4B77-B38F-547C85F84B7C.html#:~:text=Procedure%201%20Select%20Infrastructure%20%3E%20Connections%20%3E%20Integrations.,and%20select%20Deploy%20OVF%20Template.%20...%20More%20items" rel="nofollow" target="_blank">Extensibility Actions on Prem</a> integration server configured.</li><li>VRA refresh token defined. This will be used in step 0.</li><li>BlueprintID of a catalog template that will apply the lease to. We'll need this for step 2. The blueprint id can be captured easily from the URL when viewing it in the design menu. Copy everything after the %2F, for example (the bolded portion): <br /><br /><span style="font-family: courier;">https://www.mgmt.cloud.vmware.com/automation-ui/#/blueprint-ui;ash=%2Fblueprint%2Fedit%2F<b>123456-7890123456-123456789</b></span></li></ul><div>Step 0: setup Action Constant</div><div><ol style="text-align: left;"><li>Inside VRA - <b>Extensibility </b>menu, select <b>Actions </b>on the sidebar. </li><li>Select <b>Action Constants</b> and add a <b>+ New Action Constant</b></li><li>Enter the name of "refreshToken" and paste the refresh token string into the value field and select toggle to enable the <b>Encrypt the action contact value</b>. <br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiYIz4YiMi-rfWikPBOk6hOHtSprHSDlFI2axFBiWUPfaSfp67X7yO1pQt_RHVd9INoqCwY8kYkGJ13Ny8yitVn0ycn_1e7y_s3ZIirWXGlX-RNj4ymn63vxjbYpCswmiQlXYzzqwJ4YCd2wZx8Kvq0QxX9CoGAPIL72PUat6aigqriJCQMIL3spjFh" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="337" data-original-width="576" height="187" src="https://blogger.googleusercontent.com/img/a/AVvXsEiYIz4YiMi-rfWikPBOk6hOHtSprHSDlFI2axFBiWUPfaSfp67X7yO1pQt_RHVd9INoqCwY8kYkGJ13Ny8yitVn0ycn_1e7y_s3ZIirWXGlX-RNj4ymn63vxjbYpCswmiQlXYzzqwJ4YCd2wZx8Kvq0QxX9CoGAPIL72PUat6aigqriJCQMIL3spjFh" width="320" /></a></div></li><li>Click <b>SAVE</b>.</li><br /></ol></div>
<p></p><p>Step 1: create the action </p><p></p><ol style="text-align: left;"><li><b>Extensibility </b>menu, <b>Actions</b> on sidebar and click <b>+ New Action</b></li><li>Define the new action Name "SetDeploymentLease" and select the VRA Project that this will run against then click Next.</li><li>On the top, change the dropdown from PYTHON to POWERSHELL. </li><li>Copy the <a href="https://pastebin.com/NTwNha9r" rel="nofollow" target="_blank">pastebin </a>code below and paste it into the body of the action.</li><li>Under <b>Default Inputs</b>, add two more input fields (for a total of 3). These fields will be used during the run-time of the action. <br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgUvgzRSFeXXua7PlW0Ryd1myf6ydkIZL4k-npeCB8v845zZJZjsI3FdqZUXXJCgYbrAP_-55TSU4YDr4ybGnq93PaGK7d7nE0OuO_dfUfqaUFS22AZAWDXm6DpCL-40W7Fh3x6HXIVuFnqV2FNbo3_9HencV241S4ZZRWAhP1T-2mOGYqDrDgLGbK-" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="185" data-original-width="418" height="142" src="https://blogger.googleusercontent.com/img/a/AVvXsEgUvgzRSFeXXua7PlW0Ryd1myf6ydkIZL4k-npeCB8v845zZJZjsI3FdqZUXXJCgYbrAP_-55TSU4YDr4ybGnq93PaGK7d7nE0OuO_dfUfqaUFS22AZAWDXm6DpCL-40W7Fh3x6HXIVuFnqV2FNbo3_9HencV241S4ZZRWAhP1T-2mOGYqDrDgLGbK-" width="320" /></a></div><br /></li><ol><li>Default - LeasePeriod - Positive integer for the number of days to define the lease.</li><li>Default - deploymentId - can be anything, this will be sent to the action from the subscription event defined in step 2. I copied the deployment id off an existing 'test' deployment directly from the URL. (like prerequisites, it's everything after the %2F). </li><li>Action Constant - refreshToken - this will pull the value from Step 0.</li></ol><li><b>SAVE</b> the action</li></ol><div>Step 2: create a subscription - The subscription will trigger after the blueprint is run.</div><div><ol style="text-align: left;"><li><b>Extensibility</b> menu, <b>Subscriptions</b> option on sidebar and click <b>+ NEW SUBSCRIPTION</b></li><li>Give subscription name. </li><li>For <b>Event Topic</b> select "Deployment Resource Completed"</li><li>Enable the Condition and enter a (case matters) single value of: <br />event.data.blueprintId == "value from pre-requisites"</li><li><b>Action/Workflow:</b> select the new action you created in Step 1.</li><li><b>Projects:</b> Select the project you specified in step 1, item 2.</li><li><b>SAVE<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjThTNs8WSOztcwmHZmzP42QYh-Io2Vp0PRuponpj7lQHKlK_n6PxoprHx79zVWn02rPB6YLdJFr4tXg7hU1mRKgo1h9o4FjAf0XJ2afujDVjIv4B2cQ9CJ8pvMy_Nh8m3B7KJUqRsi1XIHxDnj33MPWp_TavMoHTfZGhOHVyCQfT2hbOtsvGdaoTS0" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="761" data-original-width="585" height="400" src="https://blogger.googleusercontent.com/img/a/AVvXsEjThTNs8WSOztcwmHZmzP42QYh-Io2Vp0PRuponpj7lQHKlK_n6PxoprHx79zVWn02rPB6YLdJFr4tXg7hU1mRKgo1h9o4FjAf0XJ2afujDVjIv4B2cQ9CJ8pvMy_Nh8m3B7KJUqRsi1XIHxDnj33MPWp_TavMoHTfZGhOHVyCQfT2hbOtsvGdaoTS0=w306-h400" width="306" /></a></div><br /><br /></b></li></ol><div>Testing: </div></div><div><ol style="text-align: left;"><li>Option: If valid values are entered in step 1 part 5, the test button on the Action will run. <br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgaveqixCIs6NNv6waYjm-c9B_5fwue_ZPrthUK3qQm_IX6ZL4XWry4roANt5tsSu7gBL2fQ69lmliLOzrIFl-8m_92g3TrHJxSEIIhi9BBH_FB3cUdqzF0u_jeie7tO3v9vU3dGVkW0N9LjXwb3xi2aHPM4HEfDS_MY6XIxfvxJAAYL7bYhMI1fmgE" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="116" data-original-width="522" height="71" src="https://blogger.googleusercontent.com/img/a/AVvXsEgaveqixCIs6NNv6waYjm-c9B_5fwue_ZPrthUK3qQm_IX6ZL4XWry4roANt5tsSu7gBL2fQ69lmliLOzrIFl-8m_92g3TrHJxSEIIhi9BBH_FB3cUdqzF0u_jeie7tO3v9vU3dGVkW0N9LjXwb3xi2aHPM4HEfDS_MY6XIxfvxJAAYL7bYhMI1fmgE" width="320" /></a></div><br /><br /></li><li>Option: Deploy a new machine using the catalog item defined in the prerequisites. Within a minute after the deployment completes the build, the lease should be applied via the subscription. <div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhon5o3LX4jUROK4EHjbk9r5Chz9Q8LOkM4rhyfoZbNgAz6gLulMjk-xs6KNhCP-b_FV6sOpSvKXeVECFqJLP0cIv_f1mucpE91yUcRol30OqHB6nZfmcDq7rnCuQMOviodwNFM24s3SZLq1ikOa1hCvY2bF3a-QJ2jOLwiCPV48T381zWJ5eADwSL8" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="213" data-original-width="334" height="204" src="https://blogger.googleusercontent.com/img/a/AVvXsEhon5o3LX4jUROK4EHjbk9r5Chz9Q8LOkM4rhyfoZbNgAz6gLulMjk-xs6KNhCP-b_FV6sOpSvKXeVECFqJLP0cIv_f1mucpE91yUcRol30OqHB6nZfmcDq7rnCuQMOviodwNFM24s3SZLq1ikOa1hCvY2bF3a-QJ2jOLwiCPV48T381zWJ5eADwSL8" width="320" /></a></div><br /></li></ol><div><br /></div></div><div><br /></div><div><br /></div><p></p>
<hr />
<div><script src="https://pastebin.com/embed_js/NTwNha9r"></script></div>Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-52556541143453996392021-10-11T10:47:00.000-07:002022-09-30T21:19:49.805-07:00Using VRO to query tags for a VRA-Cloud Assembly dropdown<p>We've just started building servers in our vSphere with NSX-T environment using VRA to deploy the servers. The security group placement is controlled via NSX policies that are determined by the machine's tagging. I wanted to provide a dynamic dropdown in VRA so that I did not have to recode the cloud template and subsequent service broker custom form each time a new tag value was added to vSphere. I noticed in VRA that the NSX tags were being discovered there. </p><p>This routine runs from VRO to read the tags in VRA (<a href="https://www.mgmt.cloud.vmware.com/iaas/api/swagger/ui/#/Tags/getTags" target="_blank">/iaas/api/tags</a>) with a specific KEY, and returns the VALUE in a sorted array.</p><p>Prerequisites:</p><p></p><ol style="text-align: left;"><li>VRO server integrated with VRA-Cloud Assembly. </li><li>VRA Plug-in to VRO (reference: <a href="https://blogs.vmware.com/management/2021/03/vro-vra-plugin.html" target="_blank">here</a>) - need to download and install on your VRO server.</li><li>Cloud template that needs a dropdown of tag values. </li></ol><div>Warning: Without a filter, we have over 7,000 tags coming from NSX. When I tried to query all our tags, I crashed my VRO server and needed to reboot it to kill the query. </div><div><span> </span><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9SpbnGDNaKgsA1hwKF11LZX0KquHO9Hq7zj7DScqo1cAcqNnMe9j62O_bO1KG483fNGzoAm4SgY9_5Z2k2F1JEEKEnaH1ushqM8KxtnQPb459pPgD0iBPqn62BYt_i-ON8t1A0GWZBi0/s499/defaultHost.png" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="365" data-original-width="499" height="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9SpbnGDNaKgsA1hwKF11LZX0KquHO9Hq7zj7DScqo1cAcqNnMe9j62O_bO1KG483fNGzoAm4SgY9_5Z2k2F1JEEKEnaH1ushqM8KxtnQPb459pPgD0iBPqn62BYt_i-ON8t1A0GWZBi0/s320/defaultHost.png" width="320" /></a></div>Configuration:</div><div><ol style="text-align: left;"><li>Set default VRA host </li><ol><li>VRO - select Configurations - vRA plug-in</li><li>Variables tab - click on defaultHost</li><li>Click on the value field and select the VRA host you want to query.</li><li>Save</li></ol><li>Create new Action</li><ol><li>VRO - select Library - Actions menu item </li><li>New Action</li><li>type in a name and module name </li><ol><li>typing in a 'new' name for the module will create a new module. </li></ol><li>Click on the Script tab and make sure Javascript is selected for Runtime.</li><li>On the right, click Add New Input button and create a new input</li><ol><li>name: tagFilter</li><li>type: string</li></ol><li>Change the Return type to string and check the checkbox for Array.</li><li>Paste the code below.</li><li>Save.</li></ol></ol></div>
<script src="https://pastebin.com/embed_js/hExcJ8SP"></script>Last step, TEST! Click the RUN option up top before closing the Action screen and enter a tagFilter value that matches a tag showing in your VRA - Configure - Tags. <div><br /></div><div>Replication:</div><div><ol style="text-align: left;"><li>Log into your VRA instance</li><li>Scroll down to Integrations and open the VRO integration</li><li>Click the Start Data Collection button and wait...</li></ol></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOZwP7VNS3VMiN-UTzn_fveGB5Z-FYXtyH0E6YQooiYc_bi5StFvykhEqT_WlPLysUccqGZGq4p_pj_I4f6-AuM8qaNwpr9vgGfbGMh5J2zjhxAtNgPyq71S8drgUSTyF_5Arv3YYCKhQ/s879/VROIntegration.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="296" data-original-width="879" height="108" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOZwP7VNS3VMiN-UTzn_fveGB5Z-FYXtyH0E6YQooiYc_bi5StFvykhEqT_WlPLysUccqGZGq4p_pj_I4f6-AuM8qaNwpr9vgGfbGMh5J2zjhxAtNgPyq71S8drgUSTyF_5Arv3YYCKhQ/s320/VROIntegration.png" width="320" /></a></div><br /><div><br /></div><div>Use:</div><div><ol style="text-align: left;"><li>Log into your VRA instance</li><li>Open a cloud template</li><li>Browse to the Inputs menu. </li><li>Locate or create a new input. Mine:</li><ol><li>Name: ApplicationTag</li><li>Display name: Application</li><li>Type: string</li><li>Default Value: leave blank.</li></ol><li>Scroll to the bottom of the screen and expand More Options</li><ol><li>Pairs: External Source</li><li>Action: click Select and search for the name you input into 2.3 in VRO above. </li><li>Unselect BIND and type in the tag KEY value to filter on. </li><li>SAVE to save select.</li><li>SAVE to close Input properties</li></ol><li>Test cloud template - The dropdown should load for a few seconds then complete. </li></ol><div><br /></div></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7CkLa5-CD61DNkNbfhgSOQ9ooJIy27qTpVa8fbjQoHaUloOoKGvqzINEU5ixoprZY5JJoSUzE0Km4dfNmD1MLZrQazzEZrcSdRfRaMBcgC-jSmzSsRLINi7DhIlloHB8YE_9zvH8QPp4/s564/testing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="206" data-original-width="564" height="117" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7CkLa5-CD61DNkNbfhgSOQ9ooJIy27qTpVa8fbjQoHaUloOoKGvqzINEU5ixoprZY5JJoSUzE0Km4dfNmD1MLZrQazzEZrcSdRfRaMBcgC-jSmzSsRLINi7DhIlloHB8YE_9zvH8QPp4/s320/testing.png" width="320" /></a></div><br /><div><br /></div>Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-70193892529852794642020-07-30T16:27:00.001-07:002020-07-30T16:27:50.584-07:00VRA API Programming Lessons LearnedI've been working for so long inside the closed environment of Exchange powershell, that when a co-worker suggested programming against a REST API, I sort of cringed in fear. Here was a brand new programming method that I had no concept of where to start. Luckily, VMWare vRealize Automation (<a href="https://developer.vmware.com/?socv=1&numPerPage=269&sorter=pv" target="_blank">reference</a>) has a full-featured API that you can easily write PowerShell commands against to both pull information from or push configurations up to. The documentation is well rounded with examples (written in CURL format) that can be easily translated to Powershell. <div><br /></div><div><div>Our friend on this journey will be<span style="font-family: courier;"> invoke-restMethod</span>. (<a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7" target="_blank">msdn link</a>) (yes, I have started writing my commands in camel case). This command has a few basic components:</div><div><ol style="text-align: left;"><li>headers - a variable that contains the credentials that you'll need to access this URI</li><li>uri - the URL to the aspect that you are looking to read from/post to. </li><li>method - GET information, POST information PATCH update information etc. </li><li>body - the information you'd like to post up to this interface. Usually empty when doing a GET.</li></ol><div><div><b>Headers = Authorization</b> - This differs per the API. VMWare requests that a 'refresh' token is generated in the UI, then exchanged for a bearer token. The bearer token can then be used for up to 30 minutes on API calls. AWS needs an Access key and Secret key encoded in a basic credential (i.e. 'get-credential') object. </div></div></div><div><br /></div><div><b>URI </b>- This is the basic URL to reach this object type. From my experience, this URL follows a basic format. </div><div><br /></div><div><span> </span>API URL / object</div><div><br /></div><div>For example, to query all of the VRA Cloud Accounts (<a href="https://code.vmware.com/apis/978#/Cloud%20Account/getCloudAccounts" target="_blank">reference</a>) in my environment, the URI would be </div><div><br /></div><span style="font-family: courier; font-size: small;">$myURL = "https://api.mgmt.cloud.vmware.com" + "/iaas/api/cloud-accounts"</span><div><br /></div><div><b>Method -</b> Are actions telling invoke-restMethod what is to be performed at the URL. 90% of the time I used only GET to query and POST to create. PATCH can be used to update an existing entry. (see the msdn link for more info)</div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: left;">Note: Powershell on a GET method will return an object that you can extract information from. Unfortunately, I was never able to read modify and post the same object back to a site. I ended up reading it, then creating a new body and posting that. </div><div style="text-align: left;"><span style="font-family: courier; font-size: small;"><br /></span></div></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier; font-size: small;"> $Results = Invoke-RestMethod -Uri $myURL -Method get -ContentType "application/json" -UseBasicParsing -headers $headers </span></blockquote></blockquote><div><span style="font-size: small;"> </span></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><span style="font-family: courier;"><span style="font-size: small;">$results | convertto-json</span></span></blockquote></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div style="text-align: left;"><br /></div></div><div><div style="text-align: left;">(if the query is successful, the results should look like <a href="https://code.vmware.com/apis/978#/Cloud%20Account/getCloudAccounts" target="_blank">this</a>)</div></div><div><div style="text-align: left;"><br /></div></div><div><div style="text-align: left;">whereas, you can manipulate the object:</div></div><div><div style="text-align: left;"><br /></div></div></blockquote><blockquote style="border: none; margin: 0 0 0 40px; padding: 0px;"><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div style="text-align: left;"><span style="font-family: courier;">$results.content.name </span></div></div></blockquote></blockquote><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div><div style="text-align: left;"><br /></div></div></div><div><div><div style="text-align: left;">and get "my-name"</div></div></div></blockquote><div><div><br /></div><div><br /></div><div><b>Body</b> - This was the largest part of the learning curve. The body variable is looking for a JSON formatted variable. For example, peek at the cloud-accounts <a href="https://code.vmware.com/apis/978#/Cloud%20Account/createCloudAccount" target="_blank">POST</a> method. The completed body JSON should look like something like this:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><img alt="" src="data:image/png;base64,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" style="margin-left: auto; margin-right: auto;" /></td></tr><tr><td class="tr-caption" style="text-align: center;">Sample Cloud-Account Body from code.vmware.com<br /></td></tr></tbody></table><br /><div>In Powershell, you can attempt to create this two different ways. Simply, it can be a giant text string that you format to contain all of the properties and values. Seems easy enough, but will be rather hard to support later on. The second option you can create a PowerShell hash table and convert it to JSON using the (obviously named) convertTo-JSON command. Once we identify come clues, I feel you'll agree, the hash table to JSON method is much easier.</div><div><br /></div><div><b>Observation one:</b> Items are enclosed in curly brackets. These enclose a concept or object. This will be replaced with a hash. "@{ }"</div><div><b>Observation two:</b> There are a few items enclosed in square brackets as well. These are actually arrays of results. Often when there is a one-to-many relationship. @( ) </div><div><b>Observation three</b>: Backslashes "\" surround almost all variable values. Ignore them. </div><div><b>Observation four</b>: concepts are separated by commas. Replace these with a semi-colon. </div><div><b>Observation five</b>: the colon is used to separate a key with its value. "name": "string". replace colons with an equals sign.</div><div><b>Observation six:</b> variable names are in '<a href="https://en.wikipedia.org/wiki/Camel_case">camelCase</a>' sensitive (only uppercase the first letter of the following words). This is EXTREMELY important when doing REST calls in JSON. You can build the prettiest JSON in the world, but if your variable names are not perfectly matching the case shown in the documentation, the rest call will fail. regionIds -ne RegionIDs. Going from PowerShell to JSON was a shock because of this! </div><div><br /></div><div><img alt="" src="data:image/png;base64,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" /></div><div><br /></div><div>This next example includes a multi-value array for the tags:</div><div><img alt="" src="data:image/png;base64,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" /></div><div><br /></div><div>The hardest part of the process is making sure that the hash tables and arrays are closed correctly. </div><br />Here's a snippet of what I use to create new AWS Cloud Accounts in VRA. I pass a number of variables to this JSON, but I think you can guess how they correlate to your AWS account. </div><div><br /><span style="font-family: courier; font-size: small;">$CloudRegionArray = @("us-west-2") # we only put stuff here.</span></div><div><span style="font-family: courier; font-size: small;">$NewCloudAccount = @{"accessKeyId"=$strCloudAccountAccessKey;"secretAccessKey"=$strCloudAccountSecretKey;"createDefaultZones"="true";"name"=$strCloudAccountName;"regionIds"=$CloudRegionArray;"tag"=@(@{"key"="ca";"value"=$($strCloudAccountName+"-aws")})} | convertto-json</span></div><div><span style="font-family: courier; font-size: small;"><br /></span></div><span style="font-family: courier; font-size: small;">Invoke-RestMethod -uri "https://api.mgmt.cloud.vmware.com/iaas/api/cloud-accounts-aws" -Method POST -ContentType "application/json" -headers $headers -Body $NewCloudAccount</span><div><span style="font-family: courier; font-size: small;"><br /></span></div><div><span style="font-family: courier; font-size: small;"><br /></span></div><div><span style="font-family: courier; font-size: small;"><br /></span></div></div>Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-29196419596043107792020-02-10T15:00:00.002-08:002020-02-10T15:03:34.191-08:00Using Powershell against vRealize Automation Cloud Assembly<div dir="ltr" style="text-align: left;" trbidi="on">
Over the last few weeks, I have been working to automate the steps to onboard a new customer into vRealize Automation (VRA) Cloud Assembly. The plan is as a new customer signs up with our solution, we will create a new AWS account that all of their resources will be deployed into. VRA will then be configured with a new 'cloud account'. Since we could potentially have different support areas needing access, we will create a new project to grant the permissions. With the new cloud account, we need to touch each of the flavor mappings and image mappings, create network profiles for each AWS region and storage profiles.<br />
<br />
<b>Prerequisite # 1: Get a refresh token</b><br />
A refresh token is used to initiate the authenticated communications with your environment. This refresh token is exchanged by VRA for a bearer token. You then pass this bearer token in the header of each REST call to VRA.<br />
<br />
<ol style="text-align: left;">
<li>Log into your <a href="https://console.cloud.vmware.com/" target="_blank">VMware Cloud Services</a> console.</li>
<li>Click down caret by your name in the upper right corner. </li>
<li>Select <b>My Account</b> from the dropdown menu.</li>
<li>Select <b>API Tokens</b> from the top menu. </li>
<li>Populate the form so that it includes the permissions you want to include. </li>
<li>Click the <b>Generate</b> button and it will pop up a screen with a 64 character token. </li>
<li>Copy down this code, you'll need it to populate the variable in the <span style="font-family: "courier new" , "courier" , monospace;">AuthenticateWithVRA</span> function. (<a href="https://github.com/EricWoodford/VRABlogPost/blob/master/VRA-NewAccount.ps1#L53" target="_blank">line 53</a>)</li>
</ol>
<div>
<br /></div>
<div>
<b>Prerequisite </b><b>2: AWS Programmatic Access Token</b></div>
<div>
The script configures the <a href="https://docs.vmware.com/en/vRealize-Automation/8.0/Using-and-Managing-Cloud-Assembly/GUID-EE79D1F2-9330-45C3-A1A0-F18719F56853.html" target="_blank">AWS cloud account</a> in the very beginning. Therefore script requires an AWS Access key and secret key credentials for a programmatic access account. The account will need to have <b>power user role</b> access to the AWS environment if it is to actually provision objects there. </div>
<div>
<br /></div>
<div>
Ref: <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html">https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html</a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>Prerequisite 3: Master Account configured</b></div>
<div>
To limit the scope of the script, I clone most of the configuration of an existing 'master account'. This account has the flavor and image mappings configured similar to how all new projects would be configured. To simplify the script I've embedded this value in the script. (<a href="https://github.com/EricWoodford/VRABlogPost/blob/master/VRA-NewAccount.ps1#L33" target="_blank">line 33</a>)</div>
<div>
<br /></div>
<div>
<div style="background-color: #1e1e1e; color: #d4d4d4; font-family: Consolas, "Courier New", monospace; font-size: 14px; line-height: 19px; white-space: pre;">
<div>
<span style="color: #6a9955;"># VRA Dev Account ID -> Script copies this account for new customers to be.</span></div>
<div>
<span style="color: #9cdcfe;">$DevAccountID</span> = <span style="color: #ce9178;">'abc12345667890'</span></div>
</div>
</div>
<div>
<br /></div>
<div>
This value can be pulled from the UI fairly easily. Log into VRA Cloud console, open the Cloud Account that you want to replicate then look at the URL for the project. The end of the URL, after the last %2F contains the cloud account ID to use. Mine is 29 hex digits long.</div>
<div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI3z_B4hnFV5u3KOKjzO4TXZe8kdSODgVNoGKBoqXGJqjsRjL8ih9ZlGMUURDeB3q8BWsCL2mz5Ef5F04H1qTJAF3vwNzJGoLEa3_xrv7G-oJe9l6fHAV-gGpj655YLyfLvban7ZCE2Cw/s1600/FindMyCloudAccount.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="72" data-original-width="945" height="30" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhI3z_B4hnFV5u3KOKjzO4TXZe8kdSODgVNoGKBoqXGJqjsRjL8ih9ZlGMUURDeB3q8BWsCL2mz5Ef5F04H1qTJAF3vwNzJGoLEa3_xrv7G-oJe9l6fHAV-gGpj655YLyfLvban7ZCE2Cw/s400/FindMyCloudAccount.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">sorry this is either really BIG or really small.</td></tr>
</tbody></table>
</div>
<div>
<br /></div>
<div>
Copy down that code and then locate (see reference above) and replace the ID value in the code. </div>
<div>
<br /></div>
<div>
<br /></div>
<script src="https://gist.github.com/EricWoodford/4b8f7059a9d09f97e374cabfa6bb1b26.js"></script>
<br />
<div>
The full script can be pulled from <a href="https://github.com/EricWoodford/VRABlogPost" target="_blank">GitHub</a>.</div>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-20011668361568547512018-09-19T16:24:00.000-07:002018-09-19T16:24:55.467-07:00Using a Free AWS box as Web Proxy Box<div dir="ltr" style="text-align: left;" trbidi="on">
Throughout the year, there is always a need for a remote SSH box. SSH is a reasonable way to do management of external/remote computers (command-line, bash, etc.), run DNS/network lookups from the Internet DNS servers and to even test web content without the interference of internal spam filters. Taking on this project has helped me learn about Amazon Web Services(AWS) and some automation functionality capable in the environment.<br />
<h3 style="text-align: left;">
Configure AWS SSH Proxy box</h3>
<a href="https://nimrodflores.com/web-dev/webapps/how-to-create-your-own-private-proxy-using-amazon-ec2-and-putty-on-windows" target="_blank">NimrodFlores</a> does a wonderful job explaining his process for spinning up a box in AWS, and configuring the putty client to connect. I had 3 issues with his final answer though.<br />
<br />
<ol style="text-align: left;">
<li>The post suggests using changing the default proxy settings for your browser. This is a less than ideal solution for me as I must use the similar browser for accessing the corporate resources. Using a proxy box would make this impossible. I've found that the Chrome extension "<a href="https://chrome.google.com/webstore/detail/foxyproxy-standard/gcknhkkoolaabfmlnjonogaaifnjlfnp" target="_blank">FoxyProxy</a>" is free and allows me to one-click turn-on and turn-off the proxy usage. </li>
<li>The box is never shut down. There is a hypothetical point when I would incur charges due to the amount of time the server is running. I really want the box to start on weekday mornings and stop when I am not using it. </li>
<li>By stopping the instance each night, Amazon puts a new IP address each time. This requires that you update the SSH session each time. My first idea was to attach an elastic IP address to this instance, but that generated a few cents/day charges for the 'static' address. I am now at $0.86 for the first 2 weeks of the month.I believe by getting rid of the EIP that out, I can stop that recurring charge. </li>
</ol>
<br />
I posted these in his comments section, but my post was never approved and eventually deleted. /shrug<br />
<h3 style="text-align: left;">
Part 1: Stopping and Starting the instance magically.</h3>
<b>Starting the server:</b> These <a href="https://aws.amazon.com/premiumsupport/knowledge-center/start-stop-lambda-cloudwatch/" target="_blank">instructions</a> by Amazon are good. You can configure LAMBDA scripts to stop and start your instance on scheduled CRON events. The hardest thing about configuring the script was adjusting for GMT to local time. I setup both scripts but decided to use a different stop process.<br />
<br />
<b>Stopping the server: </b>Instead of a cron job, I decided to use a CloudWatch alarm to stop an instance when the CPU utilization dropped down below a certain threshold. These AWS <a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/UsingAlarmActions.html#AddingStopActions" target="_blank">instructions</a> are useful. The biggest trick came in finding the baseline CPU utilization between actively browsing the web of one user, vs idle chatter between my workstation and the server when I left the browser open. I currently stop the instance when the CPU Utilization drops below 0.117 for 2 hours.<br />
<br />
<h3 style="text-align: left;">
Part 2 - Dynamically updating IP address</h3>
<div>
The instructions from NimrodFlores use the dynamically generated IP address from the EC2 instance page. While this is easy, it requires logging into the AWS portal each time I want to capture this, then update the putty session. (I only want to click on my shortcut on my toolbar and auto-connect to the proxy.) To work around this, I plan to use a dynamic DNS entry instead of the IP address in the putty session. </div>
<div>
<br /></div>
<b>ZoneEdit</b><br />
I use ZoneEdit for a couple reasons. First off their free for the two websites I host there. Plus they offered dynamic dns options for when I wanted to host this blog on my home PC over a dial-up DSL line (pre-blogger)<br />
<br />
For the proxy box, I decided to spin up a <a href="https://cp.zoneedit.com/manage/domains/dyn/edit.php" target="_blank">DYN record</a> for the new hostname. Enable and take note of the "DYN Authentication Token" field at the bottom. Use this as the password alternative, not your ZoneEdit password.<br />
<br />
I tried their both of their <a href="https://cp.zoneedit.com/support/dynamic/" target="_blank">options</a> on the automated dynamic DNS update, then found a post in their <a href="https://forum.zoneedit.com/index.php?threads/ddclient-issues.368/" target="_blank">forum</a> where they no longer support the ez-ipupdate option. Learned that AFTER I installed all the options required to compile the solution. The Javascript option is 'interesting' if you have a browser running on the Ubuntu server. I don't want to incur any additional costs, so smaller is better. Luckily I found DDClient.<br />
<br />
<br />
<b>Dynamic DNS - DDClient</b><br />
Here is a wonderful set of <a href="https://linhost.info/2008/12/ddclient-set-up-for-ubuntu/" target="_blank">instructions</a> posted on linhost. There are a few screens that don't match the wizard, but it steps through the install and basic configuration options. After the wizard is complete, you need to modify the configuration file. (don't do like me and reboot your server thinking it's complete after first installed.<br />
<br />
This <a href="https://www.experts-exchange.com/questions/23495211/stumped-dynamic-DNS-stopped-working-ddclient-and-www-zoneedit-com.html" target="_blank">post</a> has some other tweaks specifically regards to zoneedit you could add. No one responded to the question, but I believe that is about the time ZoneEdit was purchased by another provider.<br />
<br />
<b>Final</b><br />
Since the first of the month, I have racked up less than a $1 in charges on my AWS server. Of this, 80% was incurred during the time the EIP was running. Besides the 80 cents, I am being charged roughly a 1/3 of 1 cent for each 'configuration item'. At last check, I have 39 configuration items (i.e. $0.12). I've gone through and deleted a number of those items, but I don't think I can shrink it much more than $0.10.<br />
<br /></div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-82188555055319814142018-04-04T15:19:00.000-07:002018-04-06T12:28:49.615-07:00Powershell Hash table of Arrays<div dir="ltr" style="text-align: left;" trbidi="on">
<h4 style="text-align: left;">
The Problem</h4>
I am working on a project that has me reviewing all our groups in AD. These groups are nested in places multiple layers deep.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">All Staff </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-> Technical</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">- - > Server Team</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">- - -> Server Architecture & Build</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">- - -> Server M&O</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">- - > Network</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">-> HR</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">...</span><br />
<br />
With this, I've wanted to modify one of those nested groups, changing it so it could be replicated to O365 and used as a distribution list. Unfortunately, to do this, I need to mail-enable the on-premise copy, then have that replicate up. As this is a legacy group, it was created as a Global group. You can't mail-enable Global groups and you can't convert children of Global groups to universal. So you need to determine all the 'parent' groups of a specific child.<br />
<h4>
The Process</h4>
This script creates a hash table with 2 properties (Parents and Children) and attempts to create a flat hierarchy.<br />
<div style="text-align: left;">
</div>
<ul style="text-align: left;">
<li>"Technical" </li>
<ul>
<li><b>parents </b>are "All Staff" </li>
<li><b>children </b>are "Server Team", "Server Architecture & Build", "Server M&O" and "Network". </li>
</ul>
</ul>
<br />
Once the script is ran, it returns the hash table for all groups in the environment with these properties populated. I am still working out a bug to populate parents and children several layers up/down (for example if Server Architecture and Build has more layers underneath it).. I have worked around this by simply running the meat of the script twice. I haven't verified if possibly need a 3rd or 4th iteration to capture deeply nested groups yet. <br />
<br />
<div style="text-align: left;">
<b>A Hash table of Arrays:</b></div>
<div style="text-align: left;">
My hash table starts off as a fairly basic hash table. </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">$MyGroups = @{}</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
I then populate it with two different array objects. I pulled this concept from the <a href="https://blogs.technet.microsoft.com/heyscriptingguy/2011/12/10/create-a-hash-table-in-powershell-that-contains-hash-tables/" target="_blank">Hey Scripting Guy Blog</a>.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">#Capture all groups with email addresses populated.</span></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">$AllGroups = Get-Group -resultsize unlimited ### For DLS ## -filter {WindowsEmailAddress -like "*"} </span></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">$AllGroups | %{$MyGroups[$_.identity] = @{Parents=@(); $Children=@()}}</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Now you can access </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">$MyGroups["Technical"]</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
and get something like: </div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">Name Value</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Parents {}</span></div>
<div style="text-align: left;">
<span style="font-family: "courier new" , "courier" , monospace;">Children {}</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
As the script loops through all the groups, </div>
<div style="text-align: left;">
</div>
<ol style="text-align: left;">
<li>it populates 'children' with all member/child groups (groups that are members of this group) </li>
<li>loops through each child group and sets itself as a parent</li>
<li>copies this existing (parents of this group) parents to all those children. </li>
<li>copies children from all it's children. </li>
</ol>
<div style="text-align: left;">
So depending on the order the groups are populated, one pass appears to do 80% of the copying, but not all. If "Server Team" was reviewed before "All Staff", then they won't know about each other. As I hinted at, running this loop twice, appears to pick these changes up. </div>
<div style="text-align: left;">
<h4 style="text-align: left;">
The Script</h4>
<br /></div>
<iframe src="https://pastebin.com/embed_iframe/Q414M8uk" style="border: none; width: 100%;"></iframe><br />
<br />
The final step is something like:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$Groups = .\Report-GroupHierarchy.ps1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">$Groups["Technical"].Parents | Set-Group -Universal</span><br />
<br />
Note: On-premise AD, the object identity was the fully qualified object path, and in O365, the object identity is the same as a the object name. So depending on where you are gathering the data, you may need to enter different values.<br />
<br />
$MyGroups["Technical"]<br />
$MyGroups["example.com/Groups/Technical"]<br />
<h4>
My Own Grandpa</h4>
With a little playing around, you could use the same construct to look for "I'm My Own Grandpa" situations.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/qu_Y1wQ923g/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/qu_Y1wQ923g?feature=player_embedded" width="320"></iframe></div>
<div class="separator" style="clear: both; text-align: left;">
Let's see, this works:</div>
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$grandpa = get-group | ?{Compare-Object $Groups[$_.identity].parents $Groups[$_.identity].children -ExcludeDifferent -IncludeEqual}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<br />
<h4 style="text-align: left;">
The real problem revisited:</h4>
The reason I was reviewing groups, was to see why a user wasn't receiving any email. With 1500 distribution lists it's actually very easy for an end-user to not end up on any of the 195 distribution lists that are the children of the 'All Staff' distribution list.<br />
<br />
So where should this employee go? Let's find out who they work for.. First let's start off with a little query about direct reports..Over on the <a href="http://www.lazywinadmin.com/2014/10/powershell-who-reports-to-whom-active.html" target="_blank">LazyWinAdmin</a> there's a nice recursive script to pull all direct reports to their manager.<br />
<br />
Find manager's subordinates -> find groups these people belong to -> find the group that has a parent of "All Staff".<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">Get-ADdirectReports -samaccountname "Manager" | %{(.\memberof-O365DL.ps1 -identity $_).memberof } | select -unique identity | ?{$Groups[$_.identity].parents -eq "All Staff"}</span><br />
<span style="color: #2a2e2e; font-family: "helvetica neue" , "arial" , sans-serif; font-size: 15px;"><br /></span>
<br />
<span style="color: #2a2e2e; font-family: "helvetica neue" , "arial" , sans-serif; font-size: 15px;"><br /></span>
<span style="color: #2a2e2e; font-family: "helvetica neue" , "arial" , sans-serif; font-size: 15px;"><br /></span></div>
<iframe src="https://pastebin.com/embed_iframe/tYDGaZZb" style="border:none;width:100%"></iframe>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-68245249140687517002018-03-13T13:45:00.001-07:002018-03-14T15:37:16.064-07:00Export Exchange Properties From Resource Forest.<div dir="ltr" style="text-align: left;" trbidi="on">
This is part of an on-going article for migrating mailboxes from an on-premise Exchange 2010+ environment to Microsoft's O365. <a href="http://www.ericwoodford.com/2018/03/migration-from-on-premise-exchange-2010.html" target="_blank">See post here</a>.<h4 style="text-align: left;">
Creating the Identity Package - Mailboxes</h4>
As an Exchange admin, one of your first steps will be to sync the mailbox properties from the resource forest into the authentication domain. These mailbox properties are applied to the mailbox linked master account and synchronized to O365.<br />
<br />
When performing a migration from on-premise Exchange to O365, the migration batch/move-request process will look for specific properties (Exchange GUID, Primary SMTP Address) and fail the moves if they do not match. In addition, you'll want to modify the UserPrincipalName on the AD objects so that clients logon to OWA using their email address.<br />
<br />
<b>Exchange properties and ADObject name:</b><br />
<br />
<ol class="powershell" style="background: rgb(247, 247, 247); color: #acacac; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace, serif; font-size: 12px; margin: 0px; padding: 0px 0px 0px 55px;">
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#Name (name)</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#DisplayName (displayname)</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#SamAccountName (SamAccountName)</span></div>
</li>
<li class="li2" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de2" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#WindowsEmailAddress (mail)</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#PrimarySMTPAddress (from ProxyAddresses)</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#LegacyExchangeDN (legacyExchangeDN)</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#EmailAddresses (proxyaddresses)</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#ExchangeGUID (msExchMailboxGUID)</span></div>
</li>
<li class="li2" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de2" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#GrantSendOnBehalfTo (publicDelegates)</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="co1" style="color: green;">#ExternalEmailAddress (TargetAddress)</span></div>
</li>
</ol>
<br />
<h4 style="text-align: left;">
Part 1: Exporting Exchange properties from Exchange:</h4>
This script (testing out pastebin), is the latest revision of my script to do this. When it is run in your RF, you'll need to provide it a list of mailbox objects, the current accepted email domain (@example.com) and the tenant email domain (i.e. @ExampleTenant.onmicrosoft.com). The script will export a CSV file in the current directory containing all of the required properties.<br />
<br />
<ol class="powershell" style="background: rgb(247, 247, 247); color: #acacac; font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", monospace, serif; font-size: 12px; margin: 0px; padding: 0px 0px 0px 55px;">
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="coMULTI" style="color: green;"> $ExportNames = get-mailbox -organizationalunit "Finance" -resultsize unlimited</span></div>
</li>
<li class="li1" style="background: rgb(255, 255, 255); margin: 0px 0px 0px -6px; user-select: none;"><div class="de1" style="background-attachment: initial; background-clip: initial; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border-left: 1px solid rgb(221, 221, 221); color: #333333; margin: 0px 0px 0px -7px; padding: 0px 8px; position: relative; user-select: text; vertical-align: top;">
<span class="coMULTI" style="color: green;"> .\Export-RFToAD.ps1 -identity $ExportNames -acceptedDomain "Example.COM" -O365Domain "Contoso.OnMicrosoft.com" -department "Finance"</span></div>
</li>
</ol>
<br />
The script:<br />
<br />
<iframe src="https://pastebin.com/embed_iframe/3qK0EAZi" style="border: none; width: 100%;"></iframe>
<br />
<br />
<h4 style="text-align: left;">
Part 2: Importing the Exchange Properties</h4>
Once the CSV has been created, copy it over to the Exchange box in the authentication domain. This admin account will need to have sufficient permissions to modify all objects in this domain.<br />
<br />
Point the following script at the CSV and the Organizational Unit for where to create new user objects. <b>Note: </b>New users will typically be resource type mailboxes in the Exchange environment. They can be moved after creation to the correct folders in your AD structure. <i>Just make sure that this other OU is also synced up to the O365 tenant.</i><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">.\Import-O365IdentityPackageCSV.ps1 -CSVPath .\Finance.CSV -NewUserOU "Contoso.local\Resource Accounts"</span><br />
<br />
<br />
<iframe src="https://pastebin.com/embed_iframe/U7U4Gw7k" style="border: none; width: 100%;"></iframe>
<br />
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
If the script is unable to finish the steps, it will generate a new CSV called ".\FailedToImport.csv". Review each of these users in the authentication AD to see why they may have failed.</div>
<h4 style="text-align: left;">
Possible Failure scenarios:</h4>
<div>
<ol style="text-align: left;">
<li><b>Legacy Exchange properties</b> - Unable to apply new Exchange properties as they still have properties from a former Exchange install. "Can't enable mail user as it's already a mailbox", or "Can't contact (some server long gone) to mail enable user". I attempt to resolve this issue by checking for the setting (~ line 92). If this does not resolve the issue, check the ADUC Attribute Editor for references to the legacy environment and (you may have to) remove them. </li>
<li><b>Non-Inherited permissions </b>- If the script was unable to modify an account "ACCESS DENIED", the issue is typically because the account is not inheriting permissions. </li>
<ol>
<li>Active Directory Users and Computers</li>
<li>enable Advanced Features (view menu)</li>
<li>Open properties of the AD account for failed user.</li>
<li>Security tab -> Advanced button</li>
<li>Check the "Include Inheritable permissions from this object's parent' checkbox.</li>
</ol>
</ol>
<div>
For a quick check, I recommend doing two things:</div>
</div>
<div>
<ol style="text-align: left;">
<li>Make sure all of the objects that you mail-enabled match the CSV. We had an odd issue were the wrong GUID got applied to the wrong mailbox. Not a BIG deal as after migration, the missed GUID is still on premise and the wrong account now has the wrong displayname/email address. For example:<br /><br /><span style="font-family: "courier new" , "courier" , monospace;">import-CSV .\csvpath | ?{(get-mailuser $_.exchangeguid).displayname -ne $_.displayname}</span></li>
<li>Make sure mail-enabled accounts are in OUs that are sync'd via AAD Connect.<br /><br /><span style="font-family: "courier new" , "courier" , monospace;">import-CSV .\csvpath | %{get-mailuser $_.exchangeguid} | group organizationalUnit</span></li>
</ol>
</div>
<div>
<br /></div>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-39945511956889420792018-03-02T16:49:00.000-08:002018-03-14T16:54:09.089-07:00Migration from on-premise Exchange 2010 resource forest to EXO. <div dir="ltr" style="text-align: left;" trbidi="on">
We've just finished a year long project migrating 80,000 mailboxes from our single on-premise Exchange 2010 solution, to multiple O365 tenants. The on-premise environment is/was an <a href="https://blogs.technet.microsoft.com/exchange/2010/08/10/exchange-2010-cross-forest-mailbox-moves/" target="_blank">Exchange resource forest</a>. This means that user's logged into their local authentication domain, then via AD trust, they gained access to their mailbox hosted with us.<br />
<br />
The only difference to this diagram, instead of the Internet cloud, replace with a WAN cloud. Clients could only access mail via Outlook over the VPN to our data center. I plan to use this space to post each of the scripts that I generated for this project.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://msdnshared.blob.core.windows.net/media/2010/08/E2010CrossForestMoves1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="243" data-original-width="626" src="https://msdnshared.blob.core.windows.net/media/2010/08/E2010CrossForestMoves1.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">image source: MS Blog - <a href="https://blogs.technet.microsoft.com/exchange/2010/08/10/exchange-2010-cross-forest-mailbox-moves/" target="_blank">you had me at ehlo</a></td></tr>
</tbody></table>
<br />
To migrate from shared-multi-tenant, on-premise resource forest Exchange environment to individual O365 tenants.<br />
<br />
<ol style="text-align: left;">
<li>Create O365 tenant</li>
<li>Configure Authentication domain</li>
<ol>
<li>Update AD to 2012 R2 or better. </li>
<li>Install Exchange 2013/2016 </li>
<ol>
<li>Clean-up legacy Exchange properties</li>
<li>Extend schema for Exchange</li>
<li>Install Exchange software</li>
<li>Remove SCP record reference for auto-discover</li>
</ol>
<li>Cleanup </li>
<ol>
<li>Consolidate (if possible) OUs so that they are easy to manage.</li>
<li>Remove dead accounts.</li>
<li>Cleanup mailboxes in Exchange.</li>
<li>Update workstations so using latest Outlook (2013/2016) as available in Windows Update. Don't forget other Office applications.</li>
<li>Public Folders</li>
</ol>
</ol>
<li>Configure ADFS and AAD Connect to O365 tenant.</li>
<li>Do Mailbox <a href="http://www.ericwoodford.com/2018/03/export-exchange-properties-from.html" target="_blank">Identity Sync</a></li>
<ol>
<li>Export identity information from resource forest (RF). </li>
<li>Import identity info into similar objects in account forest.</li>
</ol>
<li>Sync mail enabled accounts and groups from account forest to O365.</li>
<ol>
<li>Review mailboxes for permissions assigned to Auth domain security groups. Include these groups in the sync.</li>
<li><br /></li>
</ol>
<li>Migrate mailboxes from RF to O365.</li>
<ol>
<li>Create migration end-point from O365 to Exchange on-premise</li>
<li>Create migration batches/move requests </li>
<li>Monitor / complete move requests.</li>
</ol>
<li>License mailboxes once migrated. </li>
<ol>
<li>Convert any resource mailboxes that came over as USERMAILBOX to shared/equipment so as to avoid using a mailbox license.</li>
</ol>
<li>Create groups and external contacts in O365 tenant. </li>
<li>Review/ fix shared mailbox permissions (security groups)</li>
</ol>
<div>
<br /></div>
Updates:<br />
<br />
<ul>
<li>3.14 - extended outline, added page for Identity Sync scripts.</li>
</ul>
<br />
<br /></div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-68283592525823122432018-02-15T17:10:00.003-08:002018-02-15T17:11:40.289-08:00Powershell: Indeterminate Inline Progress Bar<div dir="ltr" style="text-align: left;" trbidi="on">
I am currently working on removing a replicas from all of our on-premise public folders. There is quite possibly 40,000 public folders nested inside of the structure. We are looking to remove 2 copies from all replicas and the Exchange 2010 tools, while working didn't provide any progress.<br />
<br />
So, I grabbed all the 'good' replicas.<br />
<br />
<pre class="brush:ps">$firstPF = get-publicfolder ".\Top"
$GoodReplicas = $firstPF.Replicas | ?{$_ -notlike "remove this db name"}
Get-PublicFolder -recurse | ?{$_.replicas -ne $GoodReplicas} | Set-PublicFolder -replicas $GoodReplicas
</pre>
<br />
This was taking for ever and I couldn't tell if it was even running. I modified one of my <a href="http://www.ericwoodford.com/2016/05/simple-progress-bar.html" target="_blank">previous progress bars,</a> so that it would simply count to 100, then reset back to 1. Next I modified the code, to return the object I am currently parsing. This allows me to put the progress bar in-line with my code above and it keeps running.
<br />
<br />
<pre class="brush:ps">Get-PublicFolder -recurse | ?{$_.replicas -ne $GoodReplicas} | %{wp3 -passthru $_} | Set-PublicFolder -replicas $GoodReplicas
</pre>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT-5xME_J32mF9p2OnpHK7K9bANH2Uc-jil7ItLICSFSamUm8gKJG2W1DFqAe4C8O3U17Z0iozhnKeBnJfTd9P2VRnT0AnCqpxezQA9JRYY09npjk47MzHdGqPVu8qIhOtkrbeoS1msCc/s1600/sample.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="59" data-original-width="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT-5xME_J32mF9p2OnpHK7K9bANH2Uc-jil7ItLICSFSamUm8gKJG2W1DFqAe4C8O3U17Z0iozhnKeBnJfTd9P2VRnT0AnCqpxezQA9JRYY09npjk47MzHdGqPVu8qIhOtkrbeoS1msCc/s1600/sample.JPG" /></a></div>
<br />
<br />
You can see I use a few global variables. This helps maintain the counter between iterations. This also means that it will start at where you left off with the last run.
<br />
<br />
<br />
<pre class="brush:ps">function wp3 {
[CmdletBinding()] param(
[Parameter()][String]$JobName="Counter",
[Parameter()]$Passthru
)
$envVar = get-Variable -Name $JobName -Scope Global -ErrorAction SilentlyContinue -ValueOnly
$Times = $JobName+"_count"
$envVar2 = get-Variable -Name $Times -Scope Global -ErrorAction SilentlyContinue -ValueOnly
if ($EnvVar -eq $null) {
#Global Variable doesn't exist, create one called based on $JobName
$Env_WPIndex = 0
New-Variable -Name $JobName -Scope Global -Value 0 #-Visibility Private
} else {
#Use current global variable value.
$env_WPIndex = [double]$EnvVar
}
if ($envVar2 -eq $null) {
#Global Variable doesn't exist, create one called based on $JobName
$envTimeThru = 0
New-Variable -Name $Times -Scope Global -Value 0 #-Visibility Private
} else {
#Use current global variable value.
$envTimeThru = [double]$envVar2
}
Write-Progress -Activity ($JobName+"("+$envTimeThru+")") -Status $([string]$Env_WPIndex+"%") -PercentComplete $Env_WPIndex
$env_WPIndex = $env_wpIndex + 1
if ($env_wpIndex -lt 100) {
#if less then max object count, increment the global variable by one
Set-Variable -Name $JobName -Scope Global -ErrorAction SilentlyContinue -Value $env_WPIndex
} else {
$envTimeThru = $envTimeThru + 1
#if already greater than max, remove the global variable from machine.
Set-Variable -Name $JobName -Scope Global -Value 0 # -ErrorAction SilentlyContinue
}
Set-Variable -Name $Times -Scope Global -ErrorAction SilentlyContinue -Value $envTimeThru
return $Passthru
}
</pre>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-19635937245977505042018-01-08T15:23:00.000-08:002018-01-26T12:00:36.419-08:00MegaMillions Script - i.e. playing with Invoke-webrequest<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="tr_bq">
My co-worker likes to read through the powershell reddit and found this interesting little challenge. </div>
<br />
<blockquote style="border-radius: 0px; font-family: "segoe ui", frutiger, "frutiger linotype", "dejavu sans", "helvetica neue", arial, sans-serif; font-size: 14.3px; line-height: 1.42857em; margin-top: 0.357143em; padding: 0px;">
<span style="color: #f4cccc;">I had an idea for a function to generate Powerball and Megamillions numbers - multiple ticket generation segmented into separate objects and then converted into valid JSON; I did come up with something but figured this would be a nice short script challenge since it doesn't rely on an external API.</span><br />
<span style="color: #f4cccc;">Enjoy! (<a href="https://www.reddit.com/r/PowerShell/comments/7oytq7/shortest_script_challenge_powerball_and/" target="_blank">source</a>)</span></blockquote>
I thought I'd take a crack at it. So far, of the 12 responses, most of them are variants of the random number generator. After one post about 'unique' numbers, the values started getting error checking.
<br />
<br />
Results returned looks like this:<br />
Balls: 1(16%) 58(12%) 6(16%) 61(12%) 64(12%) Mega: 22<br />
<br />
<br /></div>
<pre class="brush:ps">
#megamillions
$MegaMillionsWebPage = Invoke-WebRequest http://www.megamillions.com/winning-numbers/last-25-drawings
#Extract table from web page
$mmTable = ($MegaMillionsWebPage.ParsedHtml.getElementsByTagName("TABLE") | % {$_.innertext} | % {$_.split("`n")})[1..25]
#Return mid-five columns from table (ball column)
#DrawDate Balls MegaBall Megaplier Details
$balls = $mmTable | % {$_.split(" ")[1..5]}
#Get only megaball values
$Megaball = $mmTable | % {$_.split(" ")[6]}
#Group appearance of mega ball by appearance on table
$GrpBalls = $balls | group | Sort-Object -property count -Descending
#Base line statistics of mega ball number occurence.
$BallStats = $GrpBalls | Measure-Object -Property count -min -max -average
# Have won more than 'average' number of times.
$avg = [int]$BallStats.average
While ($mostPopular.count -lt 5 -and $avg -gt 0) {
$mostPopular = $GrpBalls | ? {$_.count -gt $avg} | select -ExpandProperty Name
$avg-- #broaden scope if less than 5 results returned.
}
#Return 5 numbers from the most popular results.
$MyBalls = $mostPopular | Sort-Object {Get-Random} | select -first 5 | % {[int]$_} | Sort-Object
#Show number of appearance of each value..
$WeightedBalls = $GrpBalls | ? {$myballs -eq $_.name} | select name, @{Name = "Weight"; Expression = {[string](($_.count / 25) * 100) + "%"}}
$BallReport = $WeightedBalls | sort -Property name | %{$_.name+"("+$_.weight+")"}
write-host -NoNewline "Balls: ", ($BallReport -join (" "))
$megaGrp = $megaball | group | Sort-Object -property count -Descending
$MegaBallStats = $megaGrp | Measure-Object -Property count -min -max -average
$MegaAVG = [int]$MegaBallStats.average
#Randomly pick one of the most popular mega numbers..
$MegamostPopular = $megaGrp | ? {$_.count -eq $MegaBallStats.maximum} | select -ExpandProperty Name | Sort-Object {Get-Random} | select -first 1
write-host " Mega:",$MegamostPopular
</pre>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-84213685854853601202017-09-11T14:24:00.001-07:002018-01-26T12:01:18.323-08:00Powershell CSV Join<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
I am currently working on a fairly large project migrating mailboxes from on-premise Exchange 2010 upto Microsoft's O365. One of the issues that we're having is that mailbox permissions don't always migrate correctly. So I've developed process to capture the mailbox permissions in one form or another in a CSV prior to migration, then I reapply them after reapplying them.<br />
<br />
One of the issues experienced is that on-premise account information doesn't always match up with what's in O365. For example, I have the local Exchange / AD account information, but not necessarily what the account looks like in o365. So I wrote this script to join two CSV files based on similar properties. This way I can join a CSV containing mailbox information (i.e. SamAccountName) to the Get-MailboxPermission "USER" field.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">.\CSVJoin.PS1 -CSV1Data "c:\bin\All-Mailboxes.CSV" -CSV1Property Samaccountname -CSV2Data "c:\bin\All-MailboxPermissions.csv" -CSV2Property USER -JoinedCSV "c:\BIN\Joined-CSV.csv"</span><br />
<br />
The script will export a CSV containing all fields from CSV1 plus all the fields from CSV2 that don't overlap in name.<br />
<br /></div>
<pre class="brush:ps">
#CSVJoin.PS1
[CmdLetBinding()]
param(
[parameter(Mandatory=$true,HelpMessage="Path and filename for source CSV 1")][ValidateScript({Test-Path $_ })][string]$csv1Name,
[parameter(Mandatory=$true,HelpMessage="Propery from CSV1 to join files on.")][string]$csv1Property,
[parameter(Mandatory=$true,HelpMessage="Path and filename for source CSV 2")][ValidateScript({Test-Path $_ })][string]$Csv2Name,
[parameter(Mandatory=$true,HelpMessage="Propery from CSV2 to join files on.")][string]$csv2Property,
[parameter(Mandatory=$true,HelpMessage="Path and Name for combined CSV file")][string]$JoinedCSV
)
$csv1Data = Import-CSV $csv1Name | ?{$_.$CSV1Property -ne $null}
$csv2Data = Import-csv $Csv2Name | ?{$_.$CSV2Property -ne $null}
#Capture all the column values for each CSV file and compare them.
$csv1Members = $csv1Data[0] | Get-Member | ?{$_.membertype -eq "NoteProperty"}
$csv2Members = $csv2Data[0] | Get-Member | ?{$_.membertype -eq "NoteProperty"}
$AddCSV2members = Compare-Object $csv1Members $csv2Members | ?{$_.sideindicator -eq "=>"} | %{$_.inputobject}
#Populate HashTable with First CSV based on JOIN fields
$csv1HashTable = @{}
$csv1Data | %{$csv1HashTable[$_.$csv1Property.trim()] = $_}
#Loop through Second CSV and join fields to first CSV.
$newCSV = @()
ForEach ($c in $csv2Data) {
$Row = $csv1HashTable[$c.$csv2property.trim()]
if ($row ) {
ForEach ($m in $AddCSV2members) {
$Row | add-member -Membertype NoteProperty -Name $m.name -value $C.$($M.name) -force
}
$newCSV += $Row
}
}
if ($newCSV) {
$newCSV | Export-csv $JoinedCSV -notypeinformation
}
</pre>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-65214439336676497862017-07-06T12:33:00.001-07:002019-02-25T10:48:42.427-08:00Delete and Compress old Log Files using DOS Batch file.<div dir="ltr" style="text-align: left;" trbidi="on">
On all of our Exchange Client Access servers, I've been running my <a href="http://www.ericwoodford.com/2014/07/compress-and-delete-old-iis-logs.html" target="_blank">Compress and Delete</a> script. Unfortunately, randomly the scheduled task will fail to run the script and the log files don't get purged. This requires kicking off the process by hand to avoid server meltdown.<br />
<br />
I am thinking, that powershell may be partially at fault on some of these boxes. Permissions, or run time exceptions, may be causing the script to fail at running. So I've managed to put together this DOS Batch script that does basically the same thing.<br />
<br />
<ul style="text-align: left;">
<li>Deletes all log (and zip) files in the folder older than 30 days</li>
<li>(if finds <a href="http://www.7-zip.org/" target="_blank">7-zip</a>) It will compress all log files older than 7 days, then delete them</li>
</ul>
<div>
The one disadvantage that I see is date-stamping. In Powershell, I was going through and stamping the original log files 'last modified' date on the ZIP. This allowed me to easily trigger 30-day deletes on any file in the folder because it would maintain it's original date. I figure that if I run this scheduled task daily, it will only offset the date by 7 days (i.e. an 8 day old log file will take today's date).<br />
<br />
I am saving the following as "DOSPurgeOldLogFiles.CMD" and running it from a daily scheduled task.</div>
<div>
<br /></div>
<pre class="brush_BAT">
@Echo off
REM Folder for Log Files
Set InetLogsFolder=c:\inetpub\logs\LogFiles\W3SVC1
if NOT EXIST %InetLogsFolder% Goto :NoLogs
REM Purge all files in log folders older than 30 days old
forfiles -p %InetLogsFolder% /s /m *.* /d -30 /c "cmd /c del @path"
if NOT EXIST "c:\program files\7-Zip\7z.exe" Goto :NoZIP
REM ZIP all files older than 7 days old
for /F %%G in ('forfiles -p %InetLogsFolder% /s /m *.LOG /d -7') DO "c:\program files\7-Zip\7z.exe" a -tzip -mtc=on "%InetLogsFolder%\%%~G.zip" "%InetLogsFolder%\%%~G"
REM delete all files that are now ZIP'd
forfiles -p %INETLogsFolder% /s /m *.log /d -7 /c "cmd /c del @path"
GOTO :END
:NoLogs
Echo Cannot locate log files at %InetLogsFolder%
REM PAUSE
GOTO :END
:NoZIP
Echo Install 7-ZIP to compress log files.
:END
</pre>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-7330995804931473072017-05-12T16:51:00.001-07:002017-05-16T12:03:38.681-07:00Pull All WU Patches from Servers<div dir="ltr" style="text-align: left;" trbidi="on">
With all the concern in the news lately, we went through all our on-premise servers and reviewed the patching. This script reads all of our Exchange servers (you could replace that for a CSV of server names) and does a remote call for the Windows Update patching. The script will return an object containing each installed patch and if it was successful or not.
<br />
<pre class="brush:ps">#Report-WindowsUpdatePatching.ps1
$scriptBlock = {
$Session = New-Object -ComObject "Microsoft.Update.Session"
$Searcher = $Session.CreateUpdateSearcher()
$historyCount = $Searcher.GetTotalHistoryCount()
$Searcher.QueryHistory(0, $historyCount) | ?{$_.title -notlike "*definition update for*"} |Select-Object Title, Description, Date,
@{name="Operation"; expression={switch($_.operation){
1 {"Installation"}; 2 {"Uninstallation"}; 3 {"Other"}
}}},
@{name="Status"; expression={switch($_.resultcode){ 1 {"In Progress"}; 2 {"Succeeded"}; 3 {"Succeeded With Errors"};4 {"Failed"}; 5 {"Aborted"} }}}
}
$serverList = get-exchangeserver
$Patching = @();$serverCount = $serverList.count;$index=1
forEach ($server in $ServerList ) {
write-progress -activity "reading Windows Update" -Status $server.name -percentcomplete (($index/$serverCount)*100);$index++
$LastUpdates = Invoke-Command -ScriptBlock $scriptBlock -ComputerName $Server.name -ErrorVariable $failedWINRM
$Patching+= $lastupdates
}
return $Patching
</pre>
<pre class="brush:ps">
</pre>
<pre class="brush:ps">
</pre>
.\report-WindowsUpdatePatching.ps1 | ?{$_.title -like "*4012212*" -and $_status -eq "Failed"}
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-88502548934258040702017-03-30T16:04:00.002-07:002017-03-30T16:55:12.321-07:00Removing all the bad (email addresses)<div dir="ltr" style="text-align: left;" trbidi="on">
With moving to o365, it comes time to get serious about cleaning out all of the invalid smtp domains that we've inadvertently stamped on all our mailboxes. Those other customers where their policy was applied incorrectly and stamped across domains. Objects that moved between customers and took on both domains. That 'default' smtp domain that isn't route-able, but is out there because your customers don't really want your smtp domain stamped on everything.<br />
<br />
For this, I've developed two scripts. This first script is a bit of a blunt hammer. I will remove all domains that don't belong to this customer, plus leave any onMicrosoft.com domains.<br />
<br />
Considerations:<br />
<br />
<ol style="text-align: left;">
<li>All customers are sorted into their own OU. I am limiting my search to only their container to avoid removing email domains from objects that belong to other customers. </li>
<li>All objects have at least one valid email address that should be kept. Since this first one uses native Exchange tools, it won't remove the primary smtp address. </li>
</ol>
<pre class="brush:ps">
#Clean-NonAcceptedDomains.ps1
#Remove all but the primary smtp domain and any onmicrosoft.com domains.
[CmdLetBinding()]
param(
[parameter(Mandatory=$true)]
[string]$OU,
[parameter(Mandatory=$true)]
[string]$PrimarySMTPDomain
)
if ($ou -notlike "ou=*") {
$OuDN = get-organizationalunit $ou
$ou = $oudn.distinguishedname
}
write-host "Reviewing objects in: ",$ou
$DomainFilter = "*@"+$PrimarySMTPDomain
$AllRecipients = get-adobject -filter {mail -like $DomainFilter} -properties ProxyAddresses -searchbase $ou -resultsetsize $null
$Index=1;$objCount = $AllRecipients.count; $ModifiedDateStr = "Modified: "+$(get-date).toshortdatestring()
write-host "Found $objCount with $DomainFilter"
Foreach ($m in $AllRecipients) {
write-progress -Activity "reviewing objects" -Status $m.name -PercentComplete (($index/$objCount)*100);$Index++
$removeThese = $m.ProxyAddresses | ?{$_ -like "SMTP:*" -and $_ -notlike $DomainFilter -and $_ -notLike "*@ces.mail.ca.gov" -and $_ -notLike "*.onmicrosoft.com"} | %{$_}
if ($removeThese) {
$o = get-recipient $m.distinguishedname
$n = $null
if ($o.recipientType -eq "UserMailbox") {
$n = get-mailbox $o.identity
} elseif ($o.recipientType -like "mailUniversal*") { #Some type of group
$n = get-distributiongroup $o.identity
} elseif ($o.recipientType -like "mailuser") { #Some type of group
$n = get-mailuser $o.identity
}
if ($n -ne $null) {
$removeThese | %{write-host "removing $_ from $n"}
if ($removethese -is [string]){
#was getting errors that email address was NULL
# when trying to use foreach loop with single domain.
$Results = $n.emailaddresses.remove($RemoveThese)
} else {
$results = $removeThese | %{$n.emailaddresses.remove($_)}
break
}
if ($o.recipientType -eq "UserMailbox") {
set-mailbox -identity $n.identity -emailaddresses $n.emailaddresses -customattribute8 $ModifiedDateStr
} elseif ($o.recipientType -like "mailUniversal*") { #Some type of group
set-distributiongroup -identity $n.identity -emailaddresses $n.emailaddresses -customattribute8 $ModifiedDateStr
} elseif ($o.recipientType -like "mailuser") { #Some type of group
set-mailuser -identity $n.identity -emailaddresses $n.emailaddresses -customattribute8 $ModifiedDateStr
}
} else {
write-host "Error: $o not mailbox or group"
}
} else {
#write-host "nothing to change for $m"
}
}
</pre>
</div>Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-60329591606678383582017-01-10T16:34:00.000-08:002017-01-10T16:34:03.944-08:00MemberOf in O365<div dir="ltr" style="text-align: left;" trbidi="on">
Now that we have user's in o365, I've been trying to reproduce my on-premise Exchange 2010 scripts using technology available in O365. The biggest issue so far has been the lack of AD cmdlets. No longer can I run "get-qaduser" to pull the MemberOf and AllMemberOf properties. After numerous searches to find a way to do this, I finally decided it was going to take some powershell recursion with <span style="font-family: "courier new" , "courier" , monospace;">get-distributiongroupMember</span>.. Ugh. I was <i>that</i> close, when I stumbled on this post on <a href="https://community.spiceworks.com/scripts/show/3237-get-list-of-groups-an-office-365-user-is-a-member-of" target="_blank">Spiceworks</a>. It's a basic brute-force search, but it only took a tiny portion of the time of my recursive process. (of course, I am reading in all the groups into memory with this version, instead of live reads each group).<br />
<br />
My starts where Raven left off. My intention is to also reproduce 'allmemberof' which includes all parent groups the user is a member of. For example:<br />
<br />
Windows Engineering -> IT Staff -> California Staff -> All Staff<br />
<br />
<pre class="brush:ps">#O365MemberOf.ps1
#Finds all groups $identity belongs to in local Active Directory.
[CmdLetBinding()]
param(
[parameter(Mandatory=$true)][string]$Identity
)
write-verbose "confirming identity"
$U = get-user $identity -ea silentlycontinue
if ($U -eq $null) { write-error "Can't find $identity. Try again.";Break}
write-verbose "reading all groups into memory"
$groups = get-group -resultsize unlimited | select name, members
write-verbose "reviewing first level groups that user belongs to."
$MemberOf = $groups | ?{$_.members -contains $u}
$childgroups = $MemberOf
$AllMemberOf = $MemberOf
Do {
write-verbose "reviewing parent groups that user belongs to."
$parentGroups = ForEach ($cg in $childgroups) {
$groups | ?{ $_.members -contains $cg.name}
}
write-verbose "found some parent groups, let me check those as well. Keep climbing up the tree.."
$AllMemberOf += $parentGroups
$childgroups = $parentGroups
} While ($ParentGroups.count -gt 0) #Only stop when I reach the top.
Write-Verbose "#Create pretty answer, add to User object that we started with."
$amoj = ($AllMemberOf | select -unique Name | %{$_.name}) -join(";")
$moj = ($MemberOf | select -unique Name | %{$_.name}) -join(";")
$u | Add-Member -Name "AllMemberOf" -MemberType NoteProperty -Value $amoj
$u | Add-Member -Name "MemberOf" -MemberType NoteProperty -Value $moj
write-verbose "#Return a modified user object to requestor."
Return $u
</pre>
To use: <br />
Example 1:<br />
<br />
.\o365MemberOf.ps1 -identity "Joe User" | select MemberOf<br />
<br />
- echo first-level group membership to screen<br />
<br />
Example 2:<br />
<br />
$UserInfo = .\o365MemberOf.ps1 -identity "Joe User"<br />
$UserInfo.AllMemberOf.split(";") | get-distributiongroup<br />
<br />
- grab all group membership and find associated distribution groups.</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-35635020394329151632016-10-06T13:46:00.000-07:002016-10-28T11:45:09.416-07:00One Month With Android<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr">
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://www.optimaitalia.com/blog/wp-content/uploads/2015/01/Samsung-Windows-Phone.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://www.optimaitalia.com/blog/wp-content/uploads/2015/01/Samsung-Windows-Phone.jpg" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: 12.8px;">WP7 </span>Looking rather toyish now</td></tr>
</tbody></table>
<h4 style="text-align: left;">
I love my Windows Phone. </h4>
I was one of the two people standing outside my local AT&T store to get it on release day. My very first smartphone was a Samsung Windows Mobile 7.0. I skipped all other smart devices, turned in my Motorola flip phone and pocketed one of these.. </div>
<div dir="ltr">
<br /></div>
<div dir="ltr">
Here was such a dramatic change on cell phones seen in a LONG time. Live tiles, Xbox integration, deep in the Microsoft environment, and best of all, no stupid wall of icons (ala Windows 3.1).</div>
<div dir="ltr">
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://www.kirsle.net/creativity/articles/doswin31.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="167" src="https://www.kirsle.net/creativity/articles/doswin31.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Inspiration for iPhone and Android OS.</td></tr>
</tbody></table>
<div dir="ltr">
As the OS matured, it only got better. Tile sizes started ranging from small 1/4th size, to a large 16x grid. Live tiles are absolutely awesome! Weather? 96F. Unread message from my boss in my inbox. My son just got another XBox achievement. Meeting in hour in big conference room. Amazon order just arrived on my porch. My wife has just updated her Facebook profile. Best of all, I only logged into my home screen. "2-click access".<br />
<br />
With the OS, came some really interesting phones. My absolute favorite being the Lumia 1020 with it's glorious 41 megapixel camera. A camera that put my 10-year old DSLR to shame for basic, everyday photography. It's only real drawback was the lack of a microSD card slot, to hold those 20mb images. I loved this camera. I went as far as to purchase the extended battery case.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.kaboomlatam.com/novosite/nokia-lumia-1020-camera-grip-amazon-87.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.kaboomlatam.com/novosite/nokia-lumia-1020-camera-grip-amazon-87.jpg" height="222" width="320" /></a></div>
<br />
Trips to Disneyland were awesome because I only had to carry my cell to get a big camera; all-in-one, great low-light images, very easy package to carry around. The added battery, plus an real tripod mount on my phone made it possible to take some awesome low-light images.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://www.technobuffalo.com/wp-content/uploads/2013/07/Nokia-Lumia-1020-Sample-Tower-of-Terror-Desk-1280x722.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://www.technobuffalo.com/wp-content/uploads/2013/07/Nokia-Lumia-1020-Sample-Tower-of-Terror-Desk-1280x722.jpg" height="225" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Tower of Terror via Lumia 1020 from article <a href="http://www.technobuffalo.com/2013/07/30/a-day-at-disneyland-nokia-lumia-1020/" target="_blank">TechBuffalo</a></td></tr>
</tbody></table>
<h4 style="text-align: left;">
Sadly, the honeymoon ended.. </h4>
Lumia, the premier windows phone manufacturer was gobbled up, disassembled and soon afterwards, all their production shut down. We've had 3 mediocre (IMO) phones put out. 640, 650, and 950. A few other's, like HP put a toe in the water and spun up the Elite x3, which I <i>was</i> really excited about, but it isn't going to fix things.<br />
<br />
Things like, apps. Unless you're my uncle, who '<i>only uses his phone for calls</i>', apps play an important role on any modern handheld. I understand, programmatically the pains of supporting a platform. (i.e. scripts that no longer work due to new technologies, scripts that rely on an API that is barely supported by the vendor.) Having not just one, two, but three different operating systems and virtually hundreds of different hardware platforms is more than daunting. A developer's trepidation to simply step into a third handheld arena is palpable. Can you say 'third-wheel'?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://www.transparencyrevolution.com/wp-content/uploads/2011/03/revengeofthenerds.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="http://www.transparencyrevolution.com/wp-content/uploads/2011/03/revengeofthenerds.jpg" height="240" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Android (aka the suit), and Apple (the cheerleader) hanging with Microsoft (the nerd).</td></tr>
</tbody></table>
<h4 style="text-align: left;">
Why go with 'The Suit'? </h4>
Two reasons. I am already one foot into the google landscape. This blog is hosted blogger.com, which is ran by Google. Second, while Apple does have some nice looking <b>hardware</b>, she is very high maintenance. <span style="color: #ffe599;"><b>All about the bling.</b></span> Android is at least grounded in a bit of reality, having reasonably priced hardware. In addition, the OS is 'fairly open'. It's not impossible to customize the loader, or change the search engine to meet my eccentric whims.<br />
I started off with a work paid-for Galaxy S5. I had this for about a week for testing the deployment of new MDM solution in-house. During the week that I had this, I enjoyed being able to play <a href="https://play.google.com/store/apps/details?id=com.nianticlabs.pokemongo" target="_blank">Pokemon Go</a>, stream music via the <a href="http://amzn.to/2dbk7vJ" target="_blank">Amazon Prime</a> app, watch tv via the <a href="http://amzn.to/2dyEsuq" target="_blank">Xfinity TV</a> app, and even run <a href="http://amzn.to/2ddPraU" target="_blank">Disney Appisodes</a> for my toddler. Apps, apps and more apps. Kid in a candy store and all for free!!<br />
<br />
<i>Meanwhile on my Windows Mobile: Amazon pulls their app and replaces it with pitiful web skin. Battery on my Lumia 1520 is topping out at 2 hours on fast ring build in stand-by. Pokemon Go had my 10 year old wanting to walk the half mile to the neighborhood park. </i><br />
<br />
Even better, with a little finagling, I was able to 'win-mobile'-ify my phone. I tried looking for a decent 'live tiles' loader, but none had the real flair of Windows mobile 10, maybe WP7 where there are only 2 button sizes. <i>Bleh</i>. <a href="https://play.google.com/store/apps/details?id=com.teslacoilsw.launcher" target="_blank">Nova Launcher</a> provided both a sorted app list, and app grouping (which is 70% of what I missed). Home screen now has three groups, 'entertainment', 'games' and 'work' plus shortcut to my wife's contact. Next step, <a href="https://play.google.com/store/apps/details?id=com.microsoft.cortana" target="_blank">Cortana</a>. Holding down the home key brings up the Cortana (beta) and I get my familiar search functionality (plus my fka Bing rewards for searches). In addition, I get alerts on my Win10PC about new SMS messages, battery low, etc.. The lousy part is I've broken voice searching, 'OK Google' nothing and 'Hey Cortana' only works from inside the app.<br />
<br />
After the testing, I returned the phone and then seriously started considering Android as an option. A co-worker presented me with his 'old' work phone. He has a Samsung Galaxy S6 that he wasn't using at the moment and I could long-term borrow it. OK! Pulling the sim from my Lumia, I started rebuilding this phone. Only this time, adding widgets for weather, (Outlook) calendar and Audible.<br />
<h4 style="text-align: left;">
Android Pain points:</h4>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="http://core0.staticworld.net/images/article/2016/04/windows-10-mobile-14322-lock-screen-100656198-orig.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="http://core0.staticworld.net/images/article/2016/04/windows-10-mobile-14322-lock-screen-100656198-orig.png" height="200" width="112" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">WP Media Controls </td></tr>
</tbody></table>
<br />
<ul style="text-align: left;">
<li><b>Full media control from lock screen</b> - WP has this awesome option that if I tap the physical volume buttons, the system's media interface drops down, then I can pause currently playing media (audible, spotify, etc.). Android appears to not like that and it requires a widget on the screen to give you basic lock-screen functionality. </li>
<li><b>The land of micro-transaction</b> - Do you want weather with no ads? $2/month. Want spam call blocking? $1/month Want a new theme for your phone (no bing image of day)? $1.50. While I was used to some of this on Windows Phone, the Android market place is more wild-west. You can find a hundred free apps, each with a multitude levels of microtransaction built into it. </li>
<li><b>Loss of live tiles</b> - Widget have helped with this but it's simply not as elegant. Clicking on an appointment on my work calendar doesn't play well with the corporate MDM policies. I often get a 'your corporate policy doesn't allow this' notification because of 'crossing boundaries'. When it was the Outlook live tile providing the meeting info, it didn't complain. </li>
<li><b>Bluetooth support</b> - I was living the wireless dream. Sit down in my car, put it on the charger base, start streaming audio. Phone played music/audio via bluetooth connection to my car stereo. Unfortunately, this S6 does not work at all. The bluetooth at best will play 10 seconds of audio, then reset the connection. This will either restart the audio, rewind 5 seconds or stop playback altogether. I'm forced into using a wired 'auxiliary' cable to connect my phone to my stereo. </li>
<li><b>Bloatware and nagging native apps</b> - it was annoying on Windows that the native apps would reinstall after a full rebuild, but I COULD uninstall all of them if I wanted to. That ISP based navigation system that requires a special subscription? Gone. Family tracking app when only my wife has a phone? Gone. Android on the other hand forces me to keep all of these apps and more. In fact, it makes it REALLY hard to not use them, I continue to get notifications that the native email client needs my credentials for my work email. Guess what, my employer won't let the native app sync, we're an O365 shop, so it will NEVER work. Stop asking me and go away.. </li>
</ul>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbjY9Z80A24LjG12xroKY-FVNwOxZXBWq7rHSi513JYNlFZC8B0ynr41acGdvDQPRxQASLaSHwu43ZHlckjYeMcrov4AthOIkpCsSF72ETXtxezorRrIh2xjgzjjE2cUa5F2FtlkBrIKw/s1600/Screenshot_20161003-153836.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbjY9Z80A24LjG12xroKY-FVNwOxZXBWq7rHSi513JYNlFZC8B0ynr41acGdvDQPRxQASLaSHwu43ZHlckjYeMcrov4AthOIkpCsSF72ETXtxezorRrIh2xjgzjjE2cUa5F2FtlkBrIKw/s320/Screenshot_20161003-153836.png" width="180" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Amazon sees my giant water glass.</td></tr>
</tbody></table>
<h4 style="text-align: left;">
Android Perks:</h4>
<div>
<ul style="text-align: left;">
<li>Richer apps - Not only is the Android <b>Amazon </b>app not a web-skin, but it has awesome object scanning functionality. Point the scanner at the a barcode and it quickly find the item. Point the scanner at the water glass on my desk, it returns keywords related to that item. </li>
<li>Richer accessory ecosystem - Search Amazon for a Galaxy S6 (or work sponsored S5) case and it returns <a href="https://www.amazon.com/s/ref=sr_nr_p_n_feature_nine_bro_9?fst=as%3Aoff&rh=n%3A2335752011%2Cn%3A2407760011%2Ck%3Agalaxy+s6+case%2Cp_n_feature_nine_browse-bin%3A11034888011&keywords=galaxy+s6+case&ie=UTF8&qid=1475616950&rnid=2488708011" target="_blank">1.6 million</a> options. Search for my <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=node%3D2407760011&field-keywords=Lumia+1520+case&rh=n%3A2335752011%2Cn%3A2407760011%2Ck%3ALumia+1520+case" target="_blank">Lumia 1520</a>, you don't get even 1% of the options.</li>
<li>Microsoft apps still work - Cortana is here for my searches. OneDrive is still backing up my photos. Word, Excel, Outlook are available for my <i>work</i>. </li>
</ul>
</div>
<h4 style="text-align: left;">
Microsoft, do you want me back? Become more Disney.</h4>
<div>
While, I've quit using my Windows Phone, I still prefer the OS. Win mobile has character. Because it's a brand new OS, you've customized beyond the other two options, adding little tidbits/flavor items. I kind of think of you as a renaissance faire. Tons of character, limitless customization options and your biggest draw is homegrown apps by third party 'entertainers'. On the other hand, Android is like Disneyland. There is no originality, no individuality, no character, but they have a TON of flash, bang and glitz. Fireworks, movie-themed amusement rides and churros draw in a lot more people than jousting tournaments and turkey legs. </div>
<div>
<br /></div>
<div>
I want Disneyland on my terms. I want a phone to <span style="font-size: large;">brag about </span>with more flavor of Windows Mobile. I need <b>you</b> to be enthusiastic about selling the phone. That will make people more enthusiastic to buy it and people enthusiastic to develop for it. You and only you are going to break down that app wall. I like that the Amazon app can scan something without a barcode and return results close to it.<br />
<h4 style="text-align: left;">
How to get there ... </h4>
</div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="http://www.nytimes.com/2016/09/29/technology/blackberry-phones-earnings-q2.html?_r=0" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="98" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrDU5XJxaGzQKur1i-Dfxzpw2Q6IqhORUt5jP7G1KiH5F7LxOip_XEE8bvVtXwo1lLQWzdjm7ATVhNzBLV3UQhnc3MjOgaXHzSN3a4U4JtT-qO0rmHUczKomf1WNwojz3SSn0q7a2WIPg/s320/RIM.PNG" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Windows Mobile's future if no consumer focus. (NYTimes)</td></tr>
</tbody></table>
<div>
<a href="http://www.windowscentral.com/tag/surface-phone" target="_blank">Surface phone</a> better come true. It better be awesome, ground breaking and absolutely shiny with all those bells and whistles that that "Surface" name implies. Phone case with BT keyboard? Wireless charging?<br />
<br />
Bring back the Android bridge. This will help because we get access to the apps, and developers don't have to design for 3 different OS. You have to realize that if you're target audience is only corporate, you are becoming RIM and what's their latest phone? None. They plan to give up their 0.01% handheld marketshare to focus on MDM solutions. At least Microsoft, you have Office/o365 and Windows on desktop, I suppose there's always that.<br />
<br />
<br /></div>
<a href="https://www.amazon.com/Samsung-SM-G900V-Smartphone-Certified-Refurbished/dp/B0155CQC1I/ref=as_li_ss_il?s=wireless&ie=UTF8&qid=1475192548&sr=1-4&keywords=samsung+galaxy+s5&th=1&linkCode=li2&tag=wwwelkagorasa-20&linkId=e12784d51c82cde7d0f26b2725e51759" stndz-blocked="" style="display: none !important; display: none !important; display: none !important; display: none !important; display: none !important;" target="_blank"><img border="0" src="//ws-na.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B0155CQC1I&Format=_SL160_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=wwwelkagorasa-20" stndz-blocked="" style="display: none !important; display: none !important; display: none !important; display: none !important; display: none !important;" /></a><img alt="" border="0" height="1" src="https://ir-na.amazon-adsystem.com/e/ir?t=wwwelkagorasa-20&l=li2&o=1&a=B0155CQC1I" stndz-blocked="" style="border: none; display: none !important; display: none !important; display: none !important; display: none !important; display: none !important; margin: 0px;" width="1" />
</div>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-58865336890269364732016-06-27T16:37:00.001-07:002016-06-27T16:50:08.273-07:00Recurse Groups - All Native Tools <div dir="ltr" style="text-align: left;" trbidi="on">
Found this <a href="https://draft.blogger.com/%3Cpre%20class=%22brush:ps%22" target="_blank">post </a>from 2011 that used a slick directory searcher to find group membership. While it doesn't give parents, I was able to simply loop until I went up each chain.<br />
<pre class="brush:ps">Function AllMemberOf ($SamAccountName) {
# Based off of
# http://stackoverflow.com/questions/5072996/how-to-get-all-groups-that-a-user-is-a-member-of
$groups = ([ADSISEARCHER]"samaccountname=$($samaccountname)").Findone().Properties.memberof | ?{$_ -ne $null} | get-group
$indent = 1
$master = $groups
#$Master | get-group | %{write-host $_.name}
Do {
$parents = $Groups | %{([ADSISEARCHER]"samaccountname=$($_.SamAccountName)").FindOne().Properties.memberof} | ?{$_ -ne $null} | %{get-group $_ }
if ($parents -ne $null) {
#$Parents| get-group | %{write-host $("`t"*$indent),$_.name}
$Master += $parents
$groups = $parents
$Indent++
}
} While ($Parents -ne $null)
return $master
}
</pre>
<div>
This does roughly the same as <b>(get-aduser 'eric woodford').AllMemberof | get-group</b></div>
<div>
<br /></div>
<pre class="brush:ps">AllMemberOf $(Get-Mailbox "Eric Woodford").SamAccountName
</pre>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-30300969301840375962016-06-08T09:09:00.000-07:002016-06-08T09:24:19.325-07:00set-default-outlook-address-book-script<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<h2 style="text-align: left;">
Update June 2016.. </h2>
<div>
<br /></div>
<div>
I have a lot of requests for this script still. Unfortunately, the process that it described was designed for Outlook 2007 (and earlier). It basically had you grab the default profile registry key, then specify the correct hex value for the address book you wanted. Nothing that couldn't be done via simple .REG file import. </div>
<div>
<br /></div>
<div>
In Outlook 2010 and beyond, Microsoft changed the way the address book is specified. The script would appear to work, but Outlook wouldn't actually pull from the correct value. In my testing, it broke Outlook and I'd need to reset my profile to resolve.. Sigh.<br />
<br />
If you'd like to play around with it, I've been able to piece together that post ( with help of cached pages and people's reposting the content in other forums).<br />
<br />
To configure the script you'd need to:</div>
</div>
<ol>
<li>Set your Outlook Address Book to the view you want to set on the remote workstation. (Tools - Address Book - Tools - Options - Set show this address list first).</li>
<li>2.Export the registry key for this Outlook profile.</li>
[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\(your default Outlook profile)\9207f3e0a3b11019908b08002b2a56c2]
<li>Open the .REG file and copy the HEX code for "01023d06". For example:
00,00,00,00,dc,a7,40,c8,c0,42,10,1a,b4,b9,08,00,2b,2f,e1,82,01 </li>
<li>Edit the Set-DefaultABView.VBS file (see attached) line to use your hex code. Make sure to leave in the double-quotes.
Const DestABUsers = "00,00,00,00,dc,a7,40,c8,c0,42,10,1a,b4,b9,08,00,2b,2f,e1,82,01" </li>
</ol>
<pre class="brush:vb">'==========================================================================
'
' NAME: Set-DefaultABView.VBS
'
' Author: Eric Woodford scripts@ericwoodford.com
' DATE : 1/28/2009
'
' COMMENT: Set's the default addressbook view in Outlook 2003 and 2007.
'==========================================================================
' this value pulled from registry dump of the registry key "01023d06"
' HKCU\Software\Microsoft\WIndows NT\CurrentVersion\Windows Messaging Subystem\Profiles\My Profile\9207...5C2\
Const DestABUsers = "00,00,00,00,dc,a7,40,c8,c0,42,10,1a,b4,b9,08,00,2b,2f,e1,82,01,00,00,00,00,01,00,00,2f,67,75,69,64,3d,36,34,39,39,36,38,30,31,35,41,36,42,34,43,34,33,39,31,39,39,43,38,45,37,35,46,42,44,37,36,31,33,00"
' ################################### Helper Functions ##################################
Function ArrayAdd (Array, Value)
' add elements to an array
' Array - array
' Value - value to add to array
Dim ArrayUpper
If Ubound(Array) < 0 Then
ReDim Preserve Array(0)
ArrayUpper = 0
Else
ArrayUpper = Ubound(Array) + 1
ReDim Preserve Array(ArrayUpper)
End If
Array(ArrayUpper) = Value
End Function
Function RegistryRead (pServer, pKeyType, pSubTree, pKeyPath, pKeyName, pKeyData, pKeyDataType)
' obtain value of a registry key
' pKeyData - data value for that key
' pkeyDataType - data type for that data value for that key
' pKeyName - key name
' pKeyPath - path where the key exist
' pKeyType - type of key (0 - everytype, 1 - string, 2 - binary, 3 - dword,
' 4 - multi-string, 5 - expandable string,
' 6 - enumerate multi-keys/folders)
' pServer - server name (ex. fg206, if server name is "." then it will use the current system)
' pSubTree - registry subtree (0 - HKEY_CLASSES_ROOT, 1 - HKEY_CURRENT_USER, 2 - HKEY_LOCAL_MACHINE,
' 3 - HKEY_USERS, 5 - HKEY_CURRENT_CONFIG)
Const HKEY_CLASSES_ROOT = &H80000000, _
HKEY_CURRENT_USER = &H80000001, _
HKEY_LOCAL_MACHINE = &H80000002, _
HKEY_USERS = &H80000003, _
HKEY_CURRENT_CONFIG = &H80000005
Dim objReg
Dim Result, Server, SubTree
Result = 0
Server = pServer
Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & Server & "\root\default:StdRegProv")
Select Case pSubTree
Case 0
Subtree = HKEY_CLASSES_ROOT
Case 1
Subtree = HKEY_CURRENT_USER
Case 2
Subtree = HKEY_LOCAL_MACHINE
Case 3
Subtree = HKEY_USERS
Case 5
Subtree = HKEY_CURRENT_CONFIG
End Select
' define subtree
Select Case pKeyType
Case 0
Result = objReg.EnumValues(SubTree, pKeyPath & "\" & pKeyName, pKeyData, pKeyDataType)
' Keydata returns a single dimension array of key names while KeyDataType returns a
' a single dimension array of key types
Case 1
Result = objReg.GetStringValue(SubTree, pKeyPath, pKeyName, pKeyData)
Case 2
Result = objReg.GetBinaryValue(SubTree, pKeyPath, pKeyName, pKeyData)
' Keydata returns a single dimension array
Case 3
Result = objReg.GetDWordValue(SubTree, pKeyPath, pKeyName, pKeyData)
Case 4
Result = objReg.GetMultiStringValue(SubTree, pKeyPath, pKeyName, pKeyData)
' Keydata returns an Array
Case 5
Result = objReg.GetExpandableStringValue(SubTree, pKeyPath, pKeyName, pKeyData)
Case 6
Result = objReg.EnumKey(SubTree, pKeyPath & "\" & pKeyName, pKeyData)
' Keydata returns an object Array
End Select
' obtain key name data depending on key type
' objReg.GetStringValue - read a key in string format
' objReg.GetBinaryValue - read a key in binary format
' process single dimensional array ex: For Cnt = Lbound(Array) to Ubound(Array)
' objReg.GetDWordValue - read a key in dword format
' objReg.MutliStringValue - read a key in multi-string format/array format
' process mutlistring/array ex.: For Each Value in Array
' objReg.ExpandableStringValue - read a key in expandable string format
' objReg.EnumKey - read a key in an array format
' process array ex.: For Each Value in Array
RegistryRead = (Result = 0)
' pass value out of function, Result should be zero if registry key exist
End Function
' RegistryRead
Function RegistryWrite (pServer, pKeyType, pSubTree, pKeyPath, pKeyName, pKeyData)
' writes a value to a registry key
' pKeyData - data value for that key
' pKeyName - key name
' pKeyPath - path where the key exist
' pKeyType - type of key (1 - string, 2 - binary, 3 - dword, 4 - multi-string)
' pServer - server name (ex. fg206, if server name is "." then it will use the current system)
' pSubTree - registry subtree (0 - HKEY_CLASSES_ROOT, 1 - HKEY_CURRENT_USER, 2 - HKEY_LOCAL_MACHINE,
' 3 - HKEY_USERS, 5 - HKEY_CURRENT_CONFIG)
Const HKEY_CLASSES_ROOT = &H80000000, _
HKEY_CURRENT_USER = &H80000001, _
HKEY_LOCAL_MACHINE = &H80000002, _
HKEY_USERS = &H80000003, _
HKEY_CURRENT_CONFIG = &H80000005
' declare constants
Dim objReg
' declare objects variables
Dim Result, Server, SubTree
' declare variables
Result = 0
' initialize variables
Server = pServer
' define what server to obtain registry info (replace period with server name)
Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & Server & "\root\default:StdRegProv")
' create registry object
Select Case pSubTree
Case 0
Subtree = HKEY_CLASSES_ROOT
Case 1
Subtree = HKEY_CURRENT_USER
Case 2
Subtree = HKEY_LOCAL_MACHINE
Case 3
Subtree = HKEY_USERS
Case 5
Subtree = HKEY_CURRENT_CONFIG
End Select
' define subtree
Select Case pKeyType
Case 1
Result = objReg.SetStringValue(SubTree, pKeyPath, pKeyName, pKeyData)
Case 2
Result = objReg.SetBinaryValue(SubTree, pKeyPath, pKeyName, pKeyData)
' Keydata must be a single dimension array
Case 3
Result = objReg.SetDWordValue(SubTree, pKeyPath, pKeyName, pKeyData)
Case 4
Result = objReg.SetMultiStringValue(SubTree, pKeyPath, pKeyName, pKeyData)
' Keydata must be an Array
End Select
' set key name data depending on key type
' objReg.SetStringValue - write a key in string format
' objReg.SetBinaryValue - write a key in binary format (must be a single dimensional array)
' objReg.SetDWordValue - read a key in dword format
' objReg.SetMutliStringValue - set a key in multi-string format (must be a single dimensional array)
RegistryWrite = (Result = 0)
' pass value out of function, Result should be zero if registry write processed correctly
End Function
' RegistryWrite
Dim NewAddrBook()
ReDim NewAddrBook(-1)
For Each BinValue In Split(DestABUsers,",")
intv = CInt("&h"&binValue)
ArrayAdd NewAddrBook, intv
Next
Const OutlookDefaultAddressKey = "9207f3e0a3b11019908b08002b2a56c2", _
OutlookDefaultAddressSubKey = "01023d06", _
OutlookLookupAddressSubKey = "11023d05", _
OutlookProfileLocation = "Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem", _
OutlookProfileLocationSubKey = "Profiles"
OK = RegistryRead (".",1,1,OutlookProfileLocation&"\"&OutlookProfileLocationSubKey,"DefaultProfile",DefaultOKProfile,"")
If OK Then
KeyLocation = trim(OutlookProfileLocation & "\" & OutlookProfileLocationSubKey & "\" & DefaultOKProfile)
Ok = RegistryWrite(".", 2, 1, KeyLocation & "\" & OutlookDefaultAddressKey, OutlookDefaultAddressSubKey, NewAddrBook)
End If
' Create Log file in root drive of current workstation with date and time script ran.
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Set objShell = CreateObject("WScript.Shell")
Set colEnvironment = objShell.Environment("PROCESS")
objPath = colEnvironment("username")
Dim strOutFileName: strOutFileName = "C:\"&objpath&".log"
Set fso = CreateObject ("scripting.filesystemobject")
If fso.FileExists(strOutFileName) Then
Set Outfile = fso.OpenTextFile(strOutFileName ,ForAppending)
Else
Set Outfile = fso.OpenTextFile(strOutFileName ,ForWriting, true)
End If
Outfile.writeline Date() & " " & Time()
outfile.close
</pre>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-5322115685657945912016-05-18T16:21:00.001-07:002016-05-18T16:21:42.152-07:00Rapid Math Tricks - Mathematical Curiosity #5<div dir="ltr" style="text-align: left;" trbidi="on">
Finally digging out an old book out of the closet. I found this little math curiosity and decided to explore it further. <a href="http://www.amazon.com/Rapid-Math-Tricks-Tips-Number/dp/0471575631/ref=as_li_ss_il?ie=UTF8&qid=1463613511&sr=8-1&keywords=rapid+math+tricks&linkCode=li2&tag=wwwelkagorasa-20&linkId=ce3dd4c90f321275acc9999eda57c56c" target="_blank"><img border="0" src="//ws-na.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=0471575631&Format=_SL160_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=wwwelkagorasa-20" /></a><img alt="" border="0" height="1" src="//ir-na.amazon-adsystem.com/e/ir?t=wwwelkagorasa-20&l=li2&o=1&a=0471575631" style="border: none !important; margin: 0px !important;" width="1" /><br />
<br />
12² = 144 while 21² = 441<br />
13² = 169 while 31² = 961<br />
112² = 12,544 while 211² = 44,521<br />
...<br />
<br />
function sqr($a) { return $a*$a}<br />
function Rev($b) { return -join([System.Linq.Enumerable]::Reverse($b))}<br />
<br />
for($i=0; $i -le 1000;$i++){$ir = [int]$(rev([string]$i));$s = sqr($i);$sir = sqr($ir);$rs = rev([string]$sir);if($rs -eq $s -and $i -ne $ir){write-host $i,$s,$ir,$sir }}<br />
<br />
12 144 21 441<br />
13 169 31 961<br />
21 441 12 144<br />
31 961 13 169<br />
102 10404 201 40401<br />
103 10609 301 90601<br />
112 12544 211 44521<br />
113 12769 311 96721<br />
122 14884 221 48841<br />
201 40401 102 10404<br />
211 44521 112 12544<br />
221 48841 122 14884<br />
301 90601 103 10609<br />
311 96721 113 12769</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-18980021550690496352016-05-11T10:22:00.000-07:002016-05-11T10:22:01.389-07:00Simple Progress Bar<div dir="ltr" style="text-align: left;" trbidi="on">
I use the Powershell progress bar (write-progress) quite often. I put it into scripts that have long execution time (like cycling through all 100,000 objects in our GAL. I put it into place when manipulating data from multiple sources. I try to show some progress everywhere things happen that take more than a few seconds.<br />
<br />
Problem being, the progress bar requires some setup. You need to know how many objects you are going to touch. You need to maintain an index of what object you are currently on. That I why I started working on these two 'skins' for the progress bar.<br />
<br />
My first function uses a global variable that it maintains. This first copy takes the maximum count of items you want to review, then using a the global variable, tracks which item it's currently displaying. [0 .. Item Count]<br />
<br />
<pre class="brush:ps">Function WP {
[CmdletBinding()] param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)][Int]$ArrayItemCount,
[Parameter()][String]$JobName="Counter"
)
$OCount = $ArrayItemCount
$envVar = get-Variable -Name $JobName -Scope Global -ErrorAction SilentlyContinue -ValueOnly
if ($EnvVar -eq $null) {
#Global Variable doesn't exist, create one called based on $JobName
$Env_WPIndex = 0
New-Variable -Name $JobName -Scope Global -Value 0 #-Visibility Private
} else {
#Use current global variable value.
$env_WPIndex = [double]$EnvVar
}
#display basic progress bar
Write-Progress -Activity $JobName -Status $([string]$Env_WPIndex + ":"+[string]$ocount) -PercentComplete (($Env_WPIndex / $oCOunt)*100)
$env_WPIndex = $env_wpIndex + 1
if ($env_wpIndex -lt $OCount) {
#if less then max object count, increment the global variable by one
Set-Variable -Name $JobName -Scope Global -ErrorAction SilentlyContinue -Value $env_WPIndex
} else {
#if already greater than max, remove the global variable from machine.
Set-Variable -Name $JobName -Scope Global -Value $null # -ErrorAction SilentlyContinue
}
}</pre>
<br />
<br />
<br />
For example:<br />
<br />
<pre class="brush:ps">$Services = get-service
$Services | %{wp $Services.count; write-host $_.name}
</pre>
<br />
The problem I've found with Function WP is sometimes the global variable doesn't get reset at the end of the previous run. This causes your next progress bar to 'wrap around' (started at 11 goes to 100, then back to 11 again). I added the JobName field so that it could spin up a new global for each different iteration if you wish.<br />
<br />
The second script is much simpler, but requires you send a copy of the entire array. You pass the function a copy of your array, plus what item you're currently on, and it displays a progress bar based of it's location in the array.<br />
<br />
<pre class="brush:ps">Function WP2 {
[CmdletBinding()] param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)][array]$Array,
[Parameter(Mandatory=$true,ValueFromPipeline=$true)] $Item
)
#Find Index of current item in Array
$Index = [array]::IndexOf($array, $item)
#Count items in array
$ocount = $array.count
Write-Progress -activity "Counter" -Status $([string]$Index + ":"+[string]$ocount) -PercentComplete (($Index/$OCount)*100)
}
</pre>
<br />
For example:<br />
<br />
<pre class="brush:ps">$Services = get-service
$Services | %{wp2 $Services $_ ; write-host $_.name}
</pre>
<br />
<br />
<br /></div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-1702420199630976062016-01-12T16:13:00.003-08:002016-01-12T16:13:56.187-08:00GAL Cleanup Part 1 - Expire old contacts<div dir="ltr" style="text-align: left;" trbidi="on">
Over the 8 years that I've worked here, we've managed to virtually triple the number of contacts we host in our Global Address List. At this point, we have 90,000 mailboxes and 60,000 mail enabled contacts. I suspect that a vast majority of these contacts have not been sent to in several <b>years! </b>Heck, considering the volatile work environment, it's more than likely a good portion of those are no longer good. Customer at another company, leaves and we never delete their contact.<br />
<br />
<h3 style="text-align: left;">
Phase 1:</h3>
This got me thinking.. Read in the primary smtp address from 100 or so contacts. Search the message tracking logs (on server hosting Internet bound email) for something going to this contact. Each contact I touch, I would mark Custom Attribute 9, with date/time. If I found an entry in the tracking logs, mark Custom Attribute 10. Relatively easy script to write.<br />
<br />
#This is too easy!!<br />
get-contacts -resultsize 100 | ForEach {get-messagetrackinglog -start (7 days ago) -recipient $_.externalemailaddress.addressstring.tostring()}<br />
<br />
Unfortunately, that TOOK FOREVER!<br />
<ol style="text-align: left;">
<li>We have 12 hub transports that send out email to the Internet. This means to effectively scan for a single recipient, I'd need to scan all 12 servers. </li>
<li>We process probably a million messages each day going out to the Internet.</li>
<li>As I said, we have 60,000 mail enabled contacts.</li>
<li>We keep tracking logs back 30 days.</li>
</ol>
<div>
If I let it run in this state, we'd be scanning 1/30th contacts every day each month..</div>
<h3 style="text-align: left;">
Phase 2:</h3>
<div>
I noticed that the Recipient field on get-messagetrackinglog uses OR logic. I could technically buffer up a big handful of recipients into that field and search for them all at once. 20, I'll start with twenty recipients per search. </div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfC6SlcmslZtpQFl0lIbpB06XVOKE7TtQjV-HJUOaNpKGcWr1cAr9MWANW4IA1npMzJygkBTYwb3NVyf-nJ9E8D-JLDKzTLdMhP6nSsnTxjx8leXFKUPmrMe-SVVWIaX3h2J2zjJPPEvU/s1600/NotResults.PNG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="77" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfC6SlcmslZtpQFl0lIbpB06XVOKE7TtQjV-HJUOaNpKGcWr1cAr9MWANW4IA1npMzJygkBTYwb3NVyf-nJ9E8D-JLDKzTLdMhP6nSsnTxjx8leXFKUPmrMe-SVVWIaX3h2J2zjJPPEvU/s640/NotResults.PNG" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">These are not the results I was hoping for...</td></tr>
</tbody></table>
<div>
Evidently, I've stumbled onto a 'known bug' with the cmdlet. Your search has to be under so many characters (256 iirc). Once you exceed that, it fails. Only workaround is to reduce the # of entries in your query. At one point, I reduced my # of recipients to only 5 addresses and the script was failing. What next? Only 2 people at a time? Not much of a time savings. </div>
<div>
<br /></div>
<h3 style="text-align: left;">
Phase 3:</h3>
<div>
While walking out to my car that night I was discussing this project with a co-worker. During explaining the concept to him, I came up with an interesting idea. Scan message tracking logs for non-mailbox users. OK, it sounds worse, but it pays off. </div>
<div>
<ol style="text-align: left;">
<li>Create giant string of every accepted domain. This will be used to filter out every mailbox recipient.</li>
<li>Find and fine-tune 'directory searcher' function to validate email address is in GAL. </li>
</ol>
<div>
So here's my basic process. On each hub transport:</div>
<div>
<ul style="text-align: left;">
<li> read message tracking logs and spit out all recipients</li>
<li>filter where internal domains -notmatch external email address domain</li>
<li>check GAL to see if contact exists for recipient.</li>
<li>get mailcontact - put today's date in CA10.</li>
</ul>
</div>
<div>
Now some contacts appear to get messages hourly as part of scheduled tasks. So I created a second filter on already touched contacts. </div>
</div>
</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-2108076108485926212016-01-12T16:13:00.000-08:002016-01-12T16:13:13.111-08:00Exchange 2010 RPC Client Access Logs + Powershell + LogParser<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
I've been working on a few projects revolving around analyzing Outlook clients connecting to our email environment. The latest request was for a report that would detail how many clients from one office are connecting to email via OWA vs Outlook. While I've seen the function that details <a href="http://mikepfeiffer.net/2011/04/determine-the-number-of-active-users-on-exchange-2010-client-access-servers-with-powershell/" target="_blank">CAS connections</a>, it won't work for me. My customers range from over 45 different offices and they include vastly different #s of concurrent users. Many of the offices share the same CAS servers/pools.<br />
<br />
This got me looking at the RPC Client Access logs on each box. From here I can filter my connections based on individual mailboxes, members of the same OU, or even distribution group members. Sadly with 40,000 active users, connecting to possible 60+ CAS boxes, that's easily a 9GB of data per person of log data to go through. While I have developed fairly <a href="http://www.ericwoodford.com/2014/03/exchange-2010-outlook-client-versions.html" target="_blank">efficient powershell</a> to process this data, (it requires effectively reading in the log file for each server as a CSV and processing it individually) I believe I can do better.<br />
<h3 style="text-align: left;">
LogParser 2.2</h3>
<div>
<a href="http://exchangeserverpro.com/exchange-server-2013-planning-discovery-client-versions/" target="_blank">ExchangeServerPro</a> published an article about using LogParser to query RPC Client Access logs. Reviewing this article, I was able to pick up the basics about building a LP query for RPC client. This got me to this: </div>
<div>
<br /></div>
<pre class="brush:ps">#Set up some basics for the script.
#Default path to the RPC Client Access logs. Going to build paths to.
$LogPath = "\C$\Program Files\Exchange\Logging\RPC Client Access\"
#Default path for LogParser executable
$LogparserExec = "C:\Program Files (x86)\Log Parser 2.2\logparser.exe"
#Final Report Path
$TodayString = (Get-Date -Format "yyyyMMdd").tostring()
$ReportPath = "c:\reports\OutlookClientReport_"+$TodayString + ".CSV"
#Get names for all CAS boxes
$CASPool = get-clientaccessServer | %{$_.name}
#Build source statement for all log files. (Reading only today's logs).
[array]$logPaths = $null
$CASPool | %{$logPaths += "'\\"+$_+$LogPath+"RCA_"+$todayString + "*.log'"}
$allServers = $logPaths -join(";")
#Build one REALLY BIG query.
$Query = "SELECT EXTRACT_SUFFIX(client-name,0,'=') as Name,client-software as Software,client-software-version as Version INTO '"+$ReportPath+"' FROM "+$allServers + " where software in ('outlook.exe';'OUTLOOK.EXE') Group BY Name,Software,Version ORDER BY Name"
#Execute LogParser search
& $LogparserExec $Query -i:CSV -nSkipLines:4 # -Stats:Off
</pre>
<br />
<br />
When executed, this generates a CSV in the report path specified. It contains each customer who's connected today, and all the Outlook client version they connected with.<br />
<blockquote class="tr_bq">
Statistics:<br />
-----------<br />
Elements processed: 9140619<br />
Elements output: 53206<br />
Execution time: 135.88 seconds (00:02:15.88)</blockquote>
As the 'Client-Name' field is based off the end-user's mailbox alias and/or legacyExchangeDN, you can search for a specific user based off it.<br />
<br />
<br />
<pre class="brush:ps">#Get specific mailbox path</pre>
<pre class="brush:ps">$cn = (Get-Mailbox "End-User, Joe").LegacyExchangeDN
#Query that specifies client we are looking for.</pre>
<pre class="brush:ps">$Query = "SELECT EXTRACT_SUFFIX(client-name,0,'=') as Name,client-software as Software,client-software-version as Version INTO '"+$ReportPath+"' FROM "+$allServers + " where software in ('outlook.exe';'OUTLOOK.EXE') and client-name='"+$cn+"' Group BY Name,Software,Version ORDER BY Name"</pre>
</div>
<br />
Now you are searching all of your client access servers for Outlook connections from this specific user. My average search time for a day's log files is about the same 2 minutes per person. 2,000 people will take 4,000 minutes, or about 2 days to run.</div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-71262857439180288782016-01-12T15:57:00.000-08:002016-01-12T15:57:11.670-08:00Grabbing certain GB of Mailboxes From a DB<div dir="ltr" style="text-align: left;" trbidi="on">
We have a few databases that are reaching capacity. These DBs are around 600-700gb in the 1 TB drives we used.<br />
<br />
$TotalMoveSize=0;$move = @();get-mailbox -Database DB08 | %{$size = (get-mailboxstatistics -identity $_.identity).totalitemsize.value.tobytes();if ($totalMoveSize + $size -le 300gb){$totalMoveSize += $size;$Move+= $_.identity}}<br />
<br />
This one-liner, will read DB08, and keep adding mailboxes to an array until at or near 300gb in size.<br />
<br /></div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-14958615628229844342015-10-14T15:34:00.002-07:002015-10-15T15:11:02.969-07:00Checking OWA.. Is Mine Hacked? <div dir="ltr" style="text-align: left;" trbidi="on">
We've recently had a number of our staff ask about the recent <a href="http://go.cybereason.com/rs/996-YZT-709/images/Cybereason-Labs-Analysis-Webmail-Sever-APT.pdf" target="_blank">OWA hack</a>. To appease their fears, I went through and checked my OWA boxes to make sure that the OWAAuth.DLL hadn't been replaced or re-registered using a hacked version.<br />
<br />
<pre class="brush:ps">$servers = @("OWAServer1","OWAServer2") # get-ExchangeServer
$sbFileVersion = {
$FilePath = "C:\Program Files\Exchange\ClientAccess\Owa\auth\OWAAuth.dll"
Get-ChildItem $FilePath | Select-Object Name,length,@{Name="Version";Expression={$_.versionInfo.FileVersion}},LastWriteTime
}
Invoke-Command -ScriptBlock $sbFileVersion -ComputerName $servers # | group fileversion
$SBRegistry = {
#Return installed folder path for OWAAuth.DLL
$RegKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\66A06D0DD155D354CB4C311E0ED2EE9D"
$RegValue="AE1D439464EB1B8488741FFA028E291C"
(Get-ItemProperty $regkey).$regvalue
}
Invoke-Command -ScriptBlock $SBRegistry -ComputerName $servers
</pre>
This does two things. First off, it checks the install path of the OWAAuth.DLL and returns the version and size of the file. I skimmed these to look for differences in the installed files.<br />
<br />
Second step, it checks the registry on these same servers and looks to see what's registered. I visually checked to see if the path in the registry matches the install path. (Those registry values I found by searching one of my OWA box registries for the filename.)<br />
<br />
My server running Exchange 2010 SP3 RU10 returned:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">Name : OWAAuth.dll</span><br />
<span style="font-family: Courier New, Courier, monospace;">Length : 104632</span><br />
<span style="font-family: Courier New, Courier, monospace;">Version : 14.03.0248.002</span><br />
<span style="font-family: Courier New, Courier, monospace;">LastWriteTime : 5/27/2015 1:47:42 PM</span><br />
<span style="font-family: Courier New, Courier, monospace;">PSComputerName : OWASERVER1</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">C:\Program Files\Exchange\ClientAccess\Owa\auth\OWAAuth.dll</span></div>
Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0tag:blogger.com,1999:blog-6109225494707488136.post-38177700934735884732015-05-11T14:45:00.002-07:002015-05-11T14:48:57.226-07:00Powershell IsNumeric<div dir="ltr" style="text-align: left;" trbidi="on">
For the longest time, I've been using a visual basic trick to determine if a variable is a numeric value.<br />
<br />
<pre class="brush:ps">[reflection.assembly]::LoadWithPartialName("'Microsoft.VisualBasic")
function isNumeric([string] $a) {
$b = ([Microsoft.VisualBasic.Information]::isnumeric($a))
return $b
}
IsNumeric "12"
$True
IsNumeric "Bob"
$False
</pre>
Looking at the code, all I am doing is type-casting the variable as a integer and seeing if I get an error. So I could simply.<br />
<br />
<pre class="brush:ps">Try {
[Int]$Variable -is [Int]
} Catch {
$false
}
</pre>
<br />
So, now in my code instead of evaluating the variable if it's a numeric value, then run through a "if numeric then ____ else _____". Now I simply encapsulate my THEN _ ELSE _ portions into my Try _ Catch _.<br />
</div>
<br />
<pre class="brush:ps">
try {
$DaysInt = [int]$daysBack
$EndDate = Get-Date
$StartDate = $EndDate.AddDays(-1 * $DaysBack).ToShortDateString()
} catch {
$StartDate = Get-Date $daysback -Format g -ErrorAction silentlycontinue
if ($StartDate -ne $null) {
Write-Host "you entered a date" $StartDate
$EndDatestr = (Read-Host "Specify an End Date (enter for today)").trim()
if ($enddatestr -eq "") {
$EndDate = Get-Date
} else {
$endDate = Get-Date $EndDateStr
}
}
}
</pre>Elkagorasahttp://www.blogger.com/profile/16868176919786509891noreply@blogger.com0