Archive | PowerShell

Quick PowerShell script to run a command on every machine in an OU

I wanted to run a command on all machines in an OU. I know this documented all over the place, but this is the syntax I like:

foreach ($COMPUTER in $(Get-ADComputer -Filter * -Searchbase 'OU=SubOU,OU=TopLevelOU,DC=DOMAIN,DC=LOCAL')){
  write-host "Connecting to $($COMPUTER.Name)"
  Invoke-Command $COMPUTER.Name {ipconfig /renew}
}

Install OpenManage Server Administrator on ESXi5 via PowerCLI

Dell has changed how you install OpenManage Server Administrator on ESXi5. To do this via PowerCLI, use the following steps.

  1. Download the new vib file: OM-SrvAdmin-Dell-Web-6.5.0-542907.VIB-ESX50i_A02.zip (most recent can be found here)
  2. Extract it and upload the folder via the vSphere client (browse datastore and upload the extracted folder)
  3. Put the ESXi5 box into maintenance mode.
  4. From PowerShell with the PowerCLI installed:
    1. Connect- VIServer -Server x.x.x.x
    2. Install-VMHostPatch -HostPath /vmfs/volumes/datastore1/OM-SrvAdmin-Dell-Web-6.5.0-542907.VIB-ESX50i_A02/metadata.zip (or where ever you uploaded it)

Note: You can no longer connect directly to that web interface on port 1311 of the ESXi5 box. Now, you now have to go to a different OpenManage Server Administrator install (log out if you are auto logged in) and select “Manage remote node”. That is a pain.

PowerShell script to add Active Setup registry entries

I am interested in using Active Setup more throughout our environment. The thing I like about Active Setup is that if I screw up, it will only run once and not over and over! Kidding, but the “run one” nature of Active Setup is nice. I wanted a PowerShell function to create Active Setup registry entries, so I can script the updates on multiple machine. Here is that function:

Function JBMURPHY-AddToActiveSetup {
  Param([parameter(Mandatory = $true)]$ActiveSetupUniqueName,
	[parameter(Mandatory = $true)]$ActiveSetupStubPath,
	[parameter(Mandatory = $true)]$ActiveSetupVersion)
  $ParentKey="HKLM:Software\Microsoft\Active Setup\Installed Components"
  $Key=$ParentKey + "\" + $ActiveSetupUniqueName
  # Check for key
  if (!(Test-Path $Key)){
    New-Item -type Directory $($ParentKey + "\" + $ActiveSetupUniqueName)
  }
  else {
    write-host "Key exists"
  }
  Set-ItemProperty $($Key) -name "StubPath" -value $ActiveSetupStubPath
  Set-ItemProperty $($Key) -name "Version" -value $ActiveSetupVersion
}

Updated PowerShell to determine if a user is visiting the office

I made an error. More like an incorrect assumption in this post, specifically this code.:

Function JBMURPHY-AD-GetHomeSite {
Param($username=$(cat env:username))
foreach ($group in "OfficeGroup1","OfficeGroup2","OfficeGroup3") {
    foreach ($user in $(Get-ADGroupMember $group)){
    if ($user.SamAccountName -eq $username) {return $group}
    }
}
}

My incorrect assumption was that the AD PowerShell components were installed on every machine (they are only my machine). I needed to rewire this code above to use ADSI, since Get-ADGroupMember is not on everyone’s machine. Below is that code:

Function JBMURPHY-AD-GetHomeSite {
Param($username=$($env:USERNAME))
$groups=([AdsiSearcher]"samaccountname=$username").Findone().properties.memberof | % {([adsi]"LDAP://$_").cn}
foreach ($officegroup in "OfficeGroup2","OfficeGroup2","OfficeGroup3") {
    foreach ($group in $groups){
    if ($group -eq $officegroup) {return $group}
    }
}
}

PowerShell wrapper function to display a dialog box

I wanted a function that I could pass some text, and it would put that text in a dialog box for the user to click okay. Simple, but I will reuse it I am sure.

 

Function JBMURPHY-DisplayWindowsForm(){
Param([parameter(Mandatory = $true)]$TextToDisplay,
$Title="DefaultTitle")
		[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 
		[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
		$objForm = New-Object System.Windows.Forms.Form 
		$objForm.Text = $Title
		$objForm.Size = New-Object System.Drawing.Size(600,500) 
		$objForm.StartPosition = "CenterScreen"
		$OKButton = New-Object System.Windows.Forms.Button
		$OKButton.Location = New-Object System.Drawing.Size(250,400)
		$OKButton.Size = New-Object System.Drawing.Size(75,23)
		$OKButton.Text = "OK"
		$OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close()})
		$objForm.Controls.Add($OKButton)
		$objLabel = New-Object System.Windows.Forms.Label
		$objLabel.Location = New-Object System.Drawing.Size(10,20) 
		$objLabel.Size = New-Object System.Drawing.Size(500,400) 
		$objLabel.Text = $TextToDisplay
		$objForm.Controls.Add($objLabel) 
		$objForm.Topmost = $True
		$objForm.Add_Shown({$objForm.Activate()})
		[void] $objForm.ShowDialog()
}

PowerShell script to change default prf imported when Outlook starts up for the first time

In this previous post, I talk about how we use Office Customization Tool (OCT) and “.prf” files to deploy Office 2010. Continuing with the idea that  I want to know if a person is visiting from another office, I want to be able to switch from our default of “cached mode” to “online mode” for that visitor. I wrote this script with the logic of: IF {visiting from other office}, THEN {JBMURPHY-Install-ChangeDefaultOutlookPRF -CachedMode $false}.

This script would change where the ImportPRF registry entry points (in this example to a “.prf” file with cached mode disabled)

function JBMURPHY-Install-ChangeDefaultOutlookPRF {
 PARAM($CachedMode=$TRUE)
foreach ($PATH in (gci "HKLM:\SOFTWARE\Microsoft\Office\14.0\User Settings\*{*")){
 $ImportPRFRegPATH=$PATH.Name.Replace("HKEY_LOCAL_MACHINE","HKLM:")+"\Create\Software\Microsoft\Office\14.0\Outlook\Setup"
 If (Test-Path $ImportPRFRegPATH){
  $ImportPRFPath=$(get-itemproperty($ImportPRFRegPATH)).ImportPRF
  write-host -NoNewline "`nIportPRF=$ImportPRFPath - "
  if ($CachedMode) {
	if ($ImportPRFPath -eq "C:\PROGRA~1\MICROS~1\WITHCA~1.PRF") { write-host "Already in CachedMode"}
	else {write-host "Enabling CachedMode"
	Set-ItemProperty $ImportPRFRegPATH -Name ImportPRF -Value "C:\PROGRA~1\MICROS~1\WITHCA~1.PRF"
	write-host "Now IportPRF=$($(get-itemproperty($ImportPRFRegPATH)).ImportPRF)"
	}
  }
  else {
	if ($ImportPRFPath -eq "C:\PROGRA~1\MICROS~1\WITHOU~1.PRF") { write-host "CachedMode already turned off"}
	else {write-host "Turning Off CachedMode"
	Set-ItemProperty $ImportPRFRegPATH -Name ImportPRF -Value "C:\PROGRA~1\MICROS~1\WITHOU~1.PRF"
	write-host "Now IportPRF=$($(get-itemproperty($ImportPRFRegPATH)).ImportPRF)"
	}
  }
 }
}

PowerShell: Two functions to determine if a user is visiting the office

If you have users in distribution groups associated with each site in your organization, it should be easy to tell if a user is visiting from another office (more on why I want to do this later). First function returns the current site that the user is logging into:

Function JBMURPHY-AD-GetCurrentSite {
return [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite().name
}

The second function loops through all “office groups” and if a user is in that office, it returns the group name


Function JBMURPHY-AD-GetHomeSite {
Param($username=$(cat env:username))
foreach ($group in "OfficeGroup1","OfficeGroup2","OfficeGroup3") {
	foreach ($user in $(Get-ADGroupMember $group)){
	if ($user.SamAccountName -eq $username) {return $group}
	}
}
}

Simple I know, but I want to put these together to do some custom startup activity (maybe via “Active Startup”)

PowerShell to verify ACLs (permissions) on a folder

In my previous post, I showed how to create a new ACL and apply it to a folder. Why apply it to the folder if the folder is already set correctly? I wrote the following function to compare the ACLs of a folder to a desired set of ACLs (either created by hand (lines 3-12) or copied from an existing folder (lines 12-15).

function JBMURPHY-PERMS-ArePermsCorrect {
        Param([parameter(Mandatory = $true)]$Path,
              [parameter(Mandatory = $true)]$CorrectACL,
              [switch]$ShowCorrect)

    $folderACLs=get-acl(get-item $Path)
    if ((compare-object $($folderACLs.access) $($CorrectACL.access) -property FileSystemRights,IdentityReference,InheritanceFlags,PropagationFlags).count -gt 0) {
    Write-host "$PATH is INCORRECT"
    return $false
    }
    else {
    if ($ShowCorrect.IsPresent){write-host "$PATH is correct"}
    return $true
    }
}

If the compare-object command returns nothing, then they are the same, if they are not the same then the items returned will be greater than 0, and the first part of the conditional will be used.

PowerShell to assign permission to a folder (not copy inherited permissions)

In my previous post, I used PowerShell to change the permissions of a top level folder. In that script, I took the folder in question and copied the inherited permissions to it, and then I tinkered it to be what I wanted. I wanted to do something similar, but I wanted a set of permission that differed from the parent. Basically I wanted the folder to have unique permissions. Below is the function to do that:

function JBMURPHY-PERMS-ClientsFolderReBase {
    Param([parameter(Mandatory = $true)]$Path)
    $correctACLs = New-Object System.Security.AccessControl.DirectorySecurity
    $correctACLs.SetAccessRuleProtection($true,$true)
    $Rule_Admin = New-Object Security.AccessControl.FileSystemAccessRule("BUILTIN\Administrators",@("FullControl"),"ContainerInherit, ObjectInherit","None","Allow")
    $Rule_System = New-Object Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\SYSTEM",@("FullControl"),"ContainerInherit, ObjectInherit","None","Allow")
    $Rule_Users1 = New-Object Security.AccessControl.FileSystemAccessRule("BUILTIN\Users",@("ReadAndExecute", "Synchronize"),"None","None","Allow")
    $Rule_Users2 = New-Object Security.AccessControl.FileSystemAccessRule("BUILTIN\Users",@("Modify, Synchronize"),"ContainerInherit, ObjectInherit","InheritOnly","Allow")
    $correctACLs.AddAccessRule($Rule_Admin)
    $correctACLs.AddAccessRule($Rule_System)
    $correctACLs.AddAccessRule($Rule_Users1)
    $correctACLs.AddAccessRule($Rule_Users2)
    write-host "Changing $Path"
    set-acl $path $correctACLs
}

In line 3 I create a new ACl, and in line 4, I set the cal to not inherit parent permissions.

Lines 4-8 are the specific permissions I want to apply (they are addressing the same issue I described here)

Lines 9-12 add the new perms to the new ACL, and line 14 set the ACL of the folder to the new ACL.

A little different want o go about this, as I created an ACL from the start.

PowerShell: Return, ForEach,ForEach-Object and a pipe

I just figured this out late last night. I was pulling my hair out. If you look at the following PowerShell code

($MyArray=1,2,3,4,5) | foreach-object {
write-host $_
if ($_ -eq 3 ){return}
}

You get a result of:
1
2
3
4
5

Next, if you look at this code (the only real difference being the lack of a pipe.)

foreach ($item in ($MyArray=1,2,3,4,5)) {
write-host $item
if ($item -eq 3 ){return}
}

You get:
1
2
3

That stumped me. Why would they not produce the same thing? Then I ran across this thread. The replier said

I think because ForEach-Object processes each item in the pipeline, but the foreach statement processes the collection as a whole.

This led me to this page, and specifically this quote clears it up for me (kinda):

 . . . [the object] it is sent into the pipeline and execution continues in the next section of the pipeline.  . . . the foreach alias gets executed and the object is run through the process script block of ForEach-Object.  Once the process script block completes, the object is discarded and the next object is [sent] . . .

In summary, last night I learned that when using a pipeline, the first item is passed to the script block, the script block is run, and then the next item is passed to the script block, and so on.

That sound correct? Can you come up with a better description?