Powershell commandline with pipes error using Exchange 2010 - powershell

Being new to powershell and used to oneliners in unix I find powershell strange. The below code gives me a "too many pipes" type of error. Can anyone tell me what I am doing wrong. My last step will be to add code that adds permission if not found in the else block.
[PS] C:\Windows\system32>(Get-mailbox -identity moh | select alias, distinguishedname) | foreach-object -process { if($_.distinguishedname -match "HK1|VO[1-9]") { $alias = $_.alias; get-mailboxfolderstatistics -identity $alias | Where {$_.FolderType -eq 'Calendar'} | %{ $calpath = $_.folderpath.substring(1); Get-MailboxFolderPermission -Identity $alias":\"$calpath -User iTell | %{ if($_.AccessRights -eq 'Editor') { write-host "Editor!" } else { write-host $_.AccessRights }} } } }
I get the following error.
Pipeline not executed because a pipeline is already executing. Pipelines cannot be executed concurrently.
+ CategoryInfo : OperationStopped: (Microsoft.Power...tHelperRunspace:ExecutionCmdletHelperRunspace) [], PSInvalidOperationException
+ FullyQualifiedErrorId : RemotePipelineExecutionFailed

Got it. Had to encapsulate blocks of code with parenthesis. But I thought the pipe block was just some sort of a write lock. In here I was only getting data and hence ought to be able to read from the streams.

Related

Retrieving Computer Names That Produced an Error From Invoke-Command

I'm working on speeding the execution of a script and long story short, the core of it would look similar to this (minus Measure-Command):
$devices = Get-Content "list.txt"
Measure-Command{
try{
$Result = Invoke-Command -ComputerName $devices -ScriptBlock {
Get-LocalUser | Select-Object -Property #{N="Computer"; E={$env:COMPUTERNAME}},
Name, Enabled, PasswordChangeableDate, PasswordExpires, UserMayChangePassword,
PasswordRequired, PasswordLastSet, LastLogon,
#{n="Groups"; E={
$user = $_
Get-LocalGroup | Where-Object { $user.SID -in ($_ | Get-LocalGroupMember | Select-Object -ExpandProperty "SID") } | Select-Object -ExpandProperty "Name"
}}
} 2>> "errors.txt"
}catch{
Write-Host "Uh oh..." -ForegroundColor Red
Write-Host $Error[0]
}
}
What I'm trying to figure out is, in the case of an error on one of the devices, I want to store that device name in a separate file. In the past I was doing all of this process via a foreach loop with try/catch, which made this part very easy. I'm looking to avoid that with this solution.
Right now, I'm using 2>> "errors.txt" courtesy of this post, but this records the full error, which I don't want. Example:
[EXAMPLE DEVICE] Connecting to remote server EXAMPLE DEVICE failed with the following error message : WinRM cannot process the
request. The following error occurred while using Kerberos authentication: Cannot find the computer EXAMPLE DEVICE. Verify that
the computer exists on the network and that the name provided is spelled correctly. For more information, see the
about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (EXAMPLE DEVICE:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : NetworkPathNotFound,PSSessionStateBroken
I'd like the only record the name of the device (in this case "EXAMPLE DEVICE") in the file. Is there a way to do this?
One way to handle is to set -ErrorActions SilentlyContinue -ErrorVariable Errs.
This enables the program to flow normally without bleeding red errors all over the screen. Then you can look at the error records stored in $Errs to report on which machines had issues. In your case $Errs.TagrgetObject.
Demo might be something like
Invoke-Command -ComputerName $Computers -ScriptBlock { "Whatever..." } -ErrorAction SilentlyContinue -ErrorVariable Errs
# PostOp Check which machines had errors:
$Errs.TargetObject
This should return:
MrBogus
MrsBogus
Of course, if you want to format that more robustly you can do any arbitrary processing on the error records.

I can't get Powershell StartsWith function to work

I'm trying to create a Powershell script that prints out only certain AD groups from the Folder Permission settings. However for some reason Powershell doesn't recognize StartsWith function.
("C:\folder" | get-acl).Access | ForEach-Object { if (($_.IdentityReference).StartsWith("sl_test")) { continue }; $_ }
When I run this I got errors similar to this for every foreach object:
Method invocation failed because [System.Security.Principal.NTAccount] does not contain a method named 'StartsWith'.
At C:\temp\test.ps1:1 char:56
+ ("C:\folder" | get-acl).Access | ForEach-Object { if (($_.IdentityReference).St ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Any suggestions on how to get this to work?
IdentityReference is a [System.Security.Principal.NTAccount]according to your error message.
But .StartWith is a method on the String type. If you call a method, Powershell does no magic for you, AFAIK.
Try ... ($_.IdentityReference) -match "^sl_test" ..., which should do the implicit string conversion.
If you want the string representation of an IdentityReference (regardless of whether it's and NTAccount object or a SID), you can reference the Value property:
$_.IdentityReference.Value.StartsWith('sl_test')
Try:
Get-Acl -Path "C:\folder" | Select-Object -ExpandProperty Access | Where-Object {$_.IdentityReference -like "sl_test*" }
You can customize the output with an additional | Select-Object -Property XY

set-aduser , update several extensionattribute variables plus other attributes at once in powershell script

So I have a basic script that works when values are hardcoded. I need some help getting it to work when values are dynamic from a file:
Here is the basic script:
set-ADUser -Identity test.hsi -replace #{extensionAttribute4="LoadedFromInterface";extensionAttribute5="2";extensionAttribute6="2"} -Manager jim.james
What I want to do is read from a file using Import-CSV, loading the important columns into variables, checking for null/empty condition and then re-setting the variables if they were null. Ultimately doing the same as above but with variables that got loaded from the file. extentionAttribute5 and extensionAttribute6 would both be values from the file (sometimes null) and manager would also be a variable that is assigned from file.
Import-CSV C:\Users\user1\Documents\WTKtoAD\WTKtoAD.csv | %{$SAM = $_.SamAccountName;If ($_.PhoneTypeMobile -eq $Null) {$PhoneMobile = "NotProvided"} Else {$PhoneMobile = $_.PhoneTypeMobile};If ($_.PhoneTypeHome -eq $Null) {$PhoneHome = "NotProvided"} Else {$PhoneHome = $_.PhoneTypeHome}} | set-ADUser -Identity $SAM -Add #{extensionAttribute4="LoadedFromKronos";extensionAttribute5=$PhoneHome;extensionAttribute6=$PhoneMobile} -Manager $_.Manager
When I run the script I get the following error in Powershell ISE (x86) 'Run As Admnistrator'.
PS C:\Users\user1> Import-CSV C:\Users\user1\Documents\WTKtoAD\WTKtoAD.csv | %{$SAM = $_.SamAccountName;If ($_.PhoneTypeMobile -eq $Null) {$PhoneMobile = "NotProvided"} Else {$PhoneMobile = $_.PhoneTypeMobile};If ($_.PhoneTypeHome -eq $Null) {$PhoneHome = "NotProvided"} Else {$PhoneHome = $_.PhoneTypeHome}} | set-ADUser -Identity $SAM -Add #{extensionAttribute4="LoadedFromKronos";extensionAttribute5=$PhoneHome;extensionAttribute6=$PhoneMobile} -Manager $_.Manager
Set-ADUser : Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again.
At line:1 char:318
+ ... User -Identity $SAM -Add #{extensionAttribute4="LoadedFromKronos";extensionAttri ...
+ ~~~~
+ CategoryInfo : InvalidData: (:) [Set-ADUser], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.SetADUser
The file looks like this:
> SamAccountName,PhoneTypeMobile,PhoneTypeHome,Manager
> test.hsi,333-234-3433,'',bob.henst
The reason for the error is because you have put the Set-ADUser in the wrong place (AFTER the ForEach-Object).
You can hardly tell from your code because you are putting everything on the same line which makes it very hard to read. My advice is to give it some air. That way, mistakes are far easier to spot.
As for the code. I didn't test because I don't have AD available right now but i think this will work better:
# this is the content of the WTKtoAD.csv file
# SamAccountName,PhoneTypeMobile,PhoneTypeHome,Manager
# test.hsi,333-234-3433,'',bob.henst
Import-CSV C:\Users\user1\Documents\WTKtoAD\WTKtoAD.csv |
ForEach-Object {
$SAM = $_.SamAccountName
if ([string]::IsNullOrEmpty($_.PhoneTypeMobile)) { $PhoneMobile = "NotProvided" } else { $PhoneMobile = $_.PhoneTypeMobile }
if ([string]::IsNullOrEmpty($_.PhoneTypeHome)) { $PhoneHome = "NotProvided" } else { $PhoneHome = $_.PhoneTypeHome }
if ([string]::IsNullOrEmpty($_.Manager)) { $Manager = $null } else { $Manager = $_.Manager }
$props = #{
extensionAttribute4 = "LoadedFromKronos"
extensionAttribute5 = $PhoneHome
extensionAttribute6 = $PhoneMobile
}
Set-ADUser -Identity $SAM -Replace $props -Manager $Manager
}
As you can see, i have also put in a small test for the Manager. If in the CSV this is an empty string, it will now Clear the manager property for the user.

Powershell Script not recognising ForEach-Object as a valid cmdlet

I have writen a powershell script to make ammendments to Active Directory.
I am Getting a funny error.
Here is the script.
#imports the module active directory if it isn't there.
function add-ADmodule()
{
$modules = Get-Module | Where-Object{$_.Name -like "*ActiveDirectory*"}
if($modules -eq $null)
{
Import-Module ActiveDirectory
}
}
#import the data file
$user_csv = import-csv C:\temp\users.csv
#makes the ammendments to the AD object
function ammend-ADUsers($user_csv)
{#this is the loop to make ammendments to each object
$users_csv|ForEach-Object`
{
#assigns each user's AD object to a variable
$user_object = get-aduser -filter * `
-Properties mail |`
Where-Object{$_.mail -like $_."Email Address"}
#ammends the ad object in the above variable
set-aduser -Identity $user_object `
-OfficePhone $_."Office Number" `
-MobilePhone $_."Mobile Number" `
-StreetAddress $_."Street" `
-City $_."City" `
-PostalCode $_."PostCode"
}
}
#this is the main part of the code where it gets executed
add-ADmodule
Write-Verbose "Active Directory Module Added"
ammend-ADUsers($user_csv)
This is the error I am getting.
PS C:\Users\admin> C:\Scripts\ammend-aduser.ps1
ForEach-Object : The term 'ForEach-Object' is not recognized as the name of a
cmdlet, function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and try again.
At C:\Scripts\ammend-aduser.ps1:18 char:20
+ $users_csv|ForEach-Object`
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (ForEach-Object:String) [], Com
mandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
I am not not sure what could be causing this error or why it is happening.
Your issue is because you have not put a space between the cmdlet and the backtick character, but it would be better to not use a backtick and instead just keep the opening curly brace { on the same line:
$users_csv|ForEach-Object {
You also don't need a backtick after a pipe character. You might want to also consider using splatting instead of backticks to improve your formatting (backticks are generally discouraged as they can be hard to see and easy to use improperly). I suggest the following revision:
$users_csv | ForEach-Object {
#assigns each user's AD object to a variable
$user_object = Get-ADUser -filter * -Properties mail |
Where-Object{$_.mail -like $_."Email Address"}
$Props = #{
Identity = $user_object
OfficePhone = $_."Office Number"
MobilePhone = $_."Mobile Number"
StreetAddress = $_."Street"
City = $_."City"
PostalCode = $_."PostCode"
}
#ammends the ad object in the above variable
Set-ADUser #Props
}

Powershell: How to obtain the complete list of distribution groups

I am completely new to powershell, I have never touched this scripting language before. However, I have some backgrounds in perl and bash scripting. I am trying to implement a small script that will obtain the list of DG in Exchange server, filters the results to get only the groups that have a certain string, corresponding to the current year.
Example: check the year, in this case 2011.
Filter Name Contains 'P11'
Return only the last DG name and parse the first 7 characters.
How could I do this using powershell from an exchange server? Here is what I got:
add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
# Retrieve all DGs
$temp = Get-DistributionGroup -ResultSize Unlimited |
foreach($group in $temp)
{
write-output "GroupName:$group "
Write-output "GroupMembers:"
Get-DistributionGroupMember $group |ft displayname,alias,primarysmtpaddress
write-output ‘ ‘
}
this results in the following error:
Unexpected token 'in' in expression or statement. At
C:\Users\jfb\Desktop\NewGroupProject.ps1:7 char:18
+ foreach($group in <<<< $temp)
+ CategoryInfo : ParserError: (in:String) [],
ParseException
+ FullyQualifiedErrorId : UnexpectedToken
Remove the trailing | in the line $temp = Get-DistributionGroup -ResultSize Unlimited | and it should work fine.
What is happening is that since you had the | it is treating the foreach as a foreach-object
Try this (not tested). Create a date object,using Get-Date, and format the date to include the last two digits of the year enclosed in asterisks. This would be the wildcard for the Get-DistributionGroup cmdlet. Select the last DG object and expand its name.
$name = Get-Date -Format *Pyy*
$group = Get-DistributionGroup $name | Select-Object -Last 1 -ExpandProperty Name
if($group)
{
$group.Substring(0,7)
}