DateTime variable not parsing correctly, string works - string

I'm trying to pass a variable into a powershell command like so:
$Today = Get-Date
Get-SCSMClassInstance -Filter {ClosedDate -eq $Today}
But I get this error:
Get-SCSMClassInstance : ClosedDate_C529833E_0926_F082_C185_294CBC8BB9FD='$Today'
-- String was not recognized as a valid DateTime.
At line:1 char:1
+ Get-SCSMClassInstance -ComputerName $computer $IncidentClass -Filter
{ClosedDate ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Microsoft.Syste...InstanceComman
d:GetSCClassInstanceCommand) [Get-SCClassInstance], UnknownDatabaseException
+ FullyQualifiedErrorId : ExecutionError,Microsoft.SystemCenter.Core.Commands
.GetSCClassInstanceCommand
If I pass the string directly, it works fine, regardless of format:
Get-SCSMClassInstance -Filter {ClosedDate -eq "Friday, June 5, 2015 11:42:33 AM"}
Get-SCSMClassInstance -Filter {ClosedDate -gt "2015-6-5 11:42:33Z"}
I've tried setting the variable as DateTime as well as a string, every imaginable format - I've ensured that, when the variable is parsed, it will absolutely turn into the correct string, but nothing works.
Any ideas?

The Filter parameter is a string not scriptblock. It is working with a scriptblock in those other cases because the string form of script block is the text of the block without the surrounding braces. However, in this case, you need the variable to be substituted in the filter. Try this:
Get-SCSMClassInstance -Filter "ClosedDate -eq ""$Today"""

Related

Copy account creation date time value to an extension attribute in Active Directory

I'm trying to create a PowerShell script that copies an AD user account's creation date and time value to the extension attribute 2 field in the user's account. Here's the contents of my script:
$users = get-aduser -Filter * -Properties * -SearchBase "DC=TestDC1" | Where-Object {$_.whenCreated -ne $null }| Select-Object Samaccountname,whenCreated
foreach($user in $users)
{
set-aduser -identity $user.Samaccountname -add #{extensionAttribute2=$user.whenCreated}
}
When I run the script, it fails with the following error:
set-aduser : Invalid type 'System.DateTime'.
Parameter name: extensionAttribute2
At C:\Users\admin\Documents\PowerShell\Scripts\Update_User_AccountCreation_Attribute.ps1:7 char:1
+ set-aduser -identity $user.Samaccountname -add #{extensionAttribute2= ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (john.sp.smith:ADUser) [Set-ADUser], ArgumentException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Comm
ands.SetADUser
I believe this is because extension attributes in AD only accept text-based values by default. How can I update the script to convert the account creation date and time value to a string that I can copy to extension attribute 2?
You just need to convert the DateTime to a string. You can do that with .ToString().
set-aduser -identity $user.Samaccountname -add #{extensionAttribute2=$user.whenCreated.ToString()}
If you want to use a specific date format, you can read the documentation for ToString().

powershell psobject showing as string instead of psobject, how to convert back to psobject

I have the following variable $Obj set to the following string value:
$Obj = '#{Version=1; Name=a;}'
How do I convert this value from a string into a custom psobject?
I would like to be able to call
$Obj.Version and get the value 1. Currently this call returns nothing.
Note: Due to how I am retrieving this variable, I can't initialize it without the single quotes.
Edit:
Here is the current code:
$Command = "script.ps1 -ExtraInfo $_"
Write-Host $Command
Invoke-Expression -Command $Command
where $_ is #{Version=1; Name=a;} (without the quote)
Originally this code was written as
. script.ps1 -ExtraInfo $_
and worked, but when I added unit tests I changed it to use Invoke-Expression so that it could be testable with Pester unit tests. Is there a better way?
Edit2:
Turns out this can be solved by putting a back tic ` before the expression and that solves the issue for me. Thank you everyone for your input.
$Command = "script.ps1 -ExtraInfo `$_"
Write-Host $Command
Invoke-Expression -Command $Command
The stringified version of a [pscustomobject] instance, which resembles a hashtable literal, is not suitable for programmatic processing, as the following example demonstrates:
# Stringify a [pscustomobject] instance.
PS> "$([pscsutomobject] #{ Version=1; Name='a value' })"
#{Version=1; Name=a value} # !! Quoting of the .Name value was lost
The problem gets worse for property values that are themselves complex objects.
Since you do appear to have access to the original [pscustomobject] instance, the solution is not to stringify.
For that, you simply need to avoid up-front string interpolation by using a verbatim (single-quoted) string literal ('...') and letting Invoke-Expression - which should generally be avoided - interpret the $_ variable as its original type:
# Use *single* quotes to prevent up-front expansion.
$Command = 'script.ps1 -ExtraInfo $_'
Write-Host $Command
Invoke-Expression -Command $Command
Note that the use of a verbatim (non-interpolating) string literal makes the use of Invoke-Expression safe here, though, as Santiago Squarzon points out, there may be a better alternatives in general, and particularly in the context of Pester.
A script-block-based solution ({ ... }) that receives the object as an argument:
$Command = { script.ps1 -ExtraInfo $args[0] }
Write-Host "Calling { $Command } with argument $_"
. $Command $_
This doesn't work with Name=a because a is not a known object (or at least not defined in my PS Session). But if this is a string, this can be done with the following script:
$Obj = '#{Version=1; Name="a";}'
$s= [System.Management.Automation.ScriptBlock]::Create("New-Object -TypeName PSObject -Property $Obj")
$o = Invoke-Command -ScriptBlock $s
$o.Version
As I stated in my comment, this is odd, and should be resolved earlier in the code base. However, if that is not possible, use Invoke-Expression
like so
$newObj = Invoke-Expression $Obj
Further reading on Invoke-Expression

Variable concatenation in wrong order

I have the following:
function createFolder($folderName, $curPath)
{
$dest = $curPath + $folderName
write-host "Path is : " + $dest
# code to mess around with files etc
}
When I run this it gives me the following output:
Path is : + Test_Folder C:\Users\Me
Is there something I'm missing with the + operator, or a join/concat method that is meant for this kind of function? What is the correct way to create/concat/manipulate paths in PowerShell (I've just started using this to automate some cleanup tasks on my desktop).
EDIT: In case it makes a difference, this is what I see when I run the version command:
PS C:\Users\Me> version
BladeLogic Network Shell 8.2.01.273 (Release) [May 12 2012 21:56:02]
Copyright (C) 1996-2012 BladeLogic Inc.
Also, I'm on a work computer with no administrative privileges.
I tried:
$currentPath = "C:\Users\n0223270\Downloads"
$test = "test"
createFolder($test, $currentPath)
function createFolder($folderName, $curPath)
{
$dest = join-path -path $curPath -childpath $folderName
Write-Host $dest
}
This was the following error:
Join-Path : Cannot bind argument to parameter 'Path' because it is null.
At line:4 char:28
+ $dest = join-path -path <<<< $curPath -childpath $folderName
+ CategoryInfo : InvalidData: (:) [Join-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.JoinPathCommand
createFolder($test, $currentPath)
This isn't how you call a Powershell function. This is passing the first parameter as an array of two strings. The second parameter would be null because it's not specified and there's no default.
Try:
createFolder $test $currentPath

Build URL string

Trying to build a link with a variable and a string, but I always get a space in between them. How can I fix this?
The $sub is a SPWeb object from sharepoint.
Write-Host $sub.Url "/default.aspx"
result:
https://intra.mycompany/pages/sales /default.aspx
Put the $sub variable inside the string literal so that it is treated as one string:
Write-Host "$($sub.Url)/default.aspx"
Note that you will need to use a sub expression operator $(...) since you are accessing an attribute of $sub.
Another approach, depending on how complicated your string is, is to use the -f format operator:
Write-Host ("{0}/default.aspx" -f $sub.Url)
If you have many variables that you need to insert, it can make for cleaner and easier to read code.
Use the URL class' constructor to do the join, rather than using string manipulation. This will have the additional advantage of automatically take care of appending any slashes required.
function Join-Uri {
[CmdletBinding()]
param (
[Alias('Path','BaseUri')] #aliases so naming is consistent with Join-Path and .Net's constructor
[Parameter(Mandatory)]
[System.Uri]$Uri
,
[Alias('ChildPath')] #alias so naming is consistent with Join-Path
[Parameter(Mandatory,ValueFromPipeline)]
[string]$RelativeUri
)
process {
(New-Object -TypeName 'System.Uri' -ArgumentList $Uri,$RelativeUri)
#the above returns a URI object; if we only want the string:
#(New-Object -TypeName 'System.Uri' -ArgumentList $Uri,$RelativeUri).AbsoluteUri
}
}
$sub = new-object -TypeName PSObject -Property #{Url='http://demo'}
write-host 'Basic Demo' -ForegroundColor 'cyan'
write-host (Join-Uri $sub.Url '/default.aspx')
write-host (Join-Uri $sub.Url 'default.aspx') #NB: above we included the leading slash; here we don't; yet the output's consistent
#you can also easily do this en-masse; e.g.
write-host 'Extended Demo' -ForegroundColor 'cyan'
#('default.aspx','index.htm','helloWorld.aspx') | Join-Uri $sub.Url | select-object -ExpandProperty AbsoluteUri
Above I created a function to wrap up this functionality; but you could just as easily do something such as below:
[string]$url = (new-object -TypeName 'System.Uri' -ArgumentList ([System.Uri]'http://test'),'me').AbsoluteUri
Link to related documentation: https://msdn.microsoft.com/en-us/library/9hst1w91(v=vs.110).aspx

Can't call up SpFeature by Display Name - sharepoint 2010 power shell

I am running the sharepoint 2010 Management Shell and I am did this
Get-SPFeature –DocumentRoutingResources –Site http://sp2010 |ft -auto
Get-SPFeature : A parameter cannot be
found that matches parameter name
'Docume ntRoutingResources'. At line:1
char:40
+ Get-SPFeature -DocumentRoutingResources <<<< -Site http://sp2010 |ft -auto
+ CategoryInfo : InvalidArgument: (:) [Get-SPFeature],
ParameterB indingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.SharePoint.Powe
rShell.SPCmdletGetFeature
I am not sure why I get that since when I just do
Get-SPFeature –Site http://sp2010
It shows up
The code you entered is passing a parameter called DocumentRoutingResources to the PowerShell command, which doesn't have such a parameter.
If you want just that item returned, you can filter for it quite easily:
Get-SPFeature -site http://tskm | ? {$_.DisplayName -eq "DocumentRoutingResources" }
The "?" is a shortcut for the cmdlet "where-object".
For your specific example, the cmdlet supports the 'identity' parameter as shown here:
Get-SPFeature -identity DocumentRoutingResources -Site http://sp2010

Resources