Accessing PrivateData during Import-Module - powershell

I want to load the contents of a config.xml file and store it in $PrivateData when my module loads. Here is the definition line in my PSD1
# Private data to pass to the module specified in ModuleToProcess
PrivateData = #{'Variables'=#{};'Config'=$null}
This creates a hashtable with two items. 1) Variables is a second hashtable I use to store private variables for my module. 2) Config which will contain the values of a config.xml file. Example XML:
<Config>
<Foo>Bar</Foo>
</Config>
I can load the xml with the following line:
$PrivateData = $MyInvocation.MyCommand.Module.PrivateData
$PrivateData.Config = ([xml](Get-Content $PSScriptRoot\Config.xml | Out-String)).Config
It does not appear that I can access it in my PSM1 file. I CAN wrap it in a Cmdlet like so:
Function Initialize-TestModule {
$PrivateData = $MyInvocation.MyCommand.Module.PrivateData
$PrivateData.Config #= ([xml](Get-Content $PSScriptRoot\Config.xml | Out-String)).Config
}
But then the user would have to make a call to Import-Module and then a second call to Initialize-TestModule which is what I am trying to avoid.
If I put the code in the PSM1 it generates this error when I call Import-Module
Property 'Config' cannot be found on this object; make sure it exists and is settable.
At C:\scripts\temp\TestModule\TestModule.psm1:7 char:2
+ $PrivateData.Config = ([xml](Get-Content $PSScriptRoot\Config.xml | Out-String) ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
If I try to load in the PSD1 like this:
PrivateData = #{'Variables'=#{};'Config'=([xml](Get-Content $PSScriptRoot\Config.xml | Out-String)).Config}
I get these errors:
Import-Module : The module manifest 'C:\scripts\temp\TestModule\TestModule.psd1' could not be processed because it is
not a valid Windows PowerShell restricted language file. Please remove the elements that are not permitted by the
restricted language:
At C:\scripts\temp\TestModule\TestModule.psd1:88 char:26
+ PrivateData = #{'Config'=([xml](Get-Content $PSScriptRoot\Config.xml | Out-Strin ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Property references are not allowed in restricted language mode or a Data section.
At C:\scripts\temp\TestModule\TestModule.psd1:88 char:27
+ PrivateData = #{'Config'=([xml](Get-Content $PSScriptRoot\Config.xml | Out-Strin ...
+ ~~~~~
The type xml is not allowed in restricted language mode or a Data section.
At C:\scripts\temp\TestModule\TestModule.psd1:88 char:33
+ PrivateData = #{'Config'=([xml](Get-Content $PSScriptRoot\Config.xml | Out-Strin ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The command 'Get-Content' is not allowed in restricted language mode or a Data section.
At C:\scripts\temp\TestModule\TestModule.psd1:88 char:72
+ PrivateData = #{'Config'=([xml](Get-Content $PSScriptRoot\Config.xml | Out-Strin ...
+ ~~~~~~~~~
The command 'Out-String' is not allowed in restricted language mode or a Data section.
At line:1 char:1
+ Import-Module .\TestModule -force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (C:\scripts\temp...TestModule.psd1:String) [Import-Module], Missing
MemberException
+ FullyQualifiedErrorId : Modules_InvalidManifest,Microsoft.PowerShell.Commands.ImportModuleCommand
In my PSM1 have tried making a call to Initialize-TestModule using Invoke-Command and Start-Job both of which failed. So has anyone managed to access $PrivateData during Import-Module?

You will likely need to access the private data using the $MyInvocation variable. However, I've only gotten it to work by calling it from within a function. To load it to a variable in the PSM1 file I call the function from there. I found out about this from https://social.technet.microsoft.com/Forums/windowsserver/en-US/9620af9a-0323-460c-b3e8-68a73715f99d/module-scoped-variable?forum=winserverpowershell.
function Get-PD
{
[CmdletBinding()]
Param()
Begin{}
Process
{
$MyInvocation.MyCommand.Module.PrivateData
}
End{}
}
$MyPD = Get-PD

Related

Add xml object to xml file in PowerShell

I am trying to create an RDCMan file (.rdg xml file) using PowerShell. I have started by defining this template
$newFileTemplate = '<?xml version="1.0" encoding="utf-8"?>
<RDCMan programVersion="2.7" schemaVersion="3">
<file>
<properties>
<expanded>False</expanded>
<name>Office Servers</name>
</properties>
<displaySettings inherit="None">
<liveThumbnailUpdates>True</liveThumbnailUpdates>
<allowThumbnailSessionInteraction>False</allowThumbnailSessionInteraction>
<showDisconnectedThumbnails>True</showDisconnectedThumbnails>
<thumbnailScale>1</thumbnailScale>
<smartSizeDockedWindows>True</smartSizeDockedWindows>
<smartSizeUndockedWindows>False</smartSizeUndockedWindows>
</displaySettings>
</file>
</RDCMan>
'
before creating an xml object like so
$File = 'D:\Test.rdg'
Set-Content $File $newFileTemplate
[XML]$XMLFile = [XML](Get-Content $File)
I would then like to define a function for adding a group of servers
# This function adds a new group element
Function Add-NewGroup($GroupName,$RDCManFile) {
[xml]$GroupXML = #"
<group>
<properties>
<expanded>False</expanded>
<name>$GroupName</name>
</properties>
</group>
"#
$Child = $RDCManFile.ImportNode($GroupXML.group, $true)
$RDCManFile.Configuration.AppendChild($Child)
}
And call it by running
Add-NewGroup('DCs',$XMLFile)
This would allow me to populate the xml file with all of the OUs in AD.
Is anyone able to tell me where I am going wrong?
Thanks
Update: The error I am getting is
You cannot call a method on a null-valued expression.
At D:\Users\user\Desktop\Projects\RDCMan\Create-RDG.ps1:179 char:5
+ $Child = $RDCManFile.ImportNode($GroupXML.group, $true)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At D:\Users\user\Desktop\Projects\RDCMan\Create-RDG.ps1:180 char:5
+ $RDCManFile.Configuration.AppendChild($Child)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
And I am trying to do what was suggested here https://stackoverflow.com/a/29693625/2165019
The property 'Configuration' cannot be found on this object. Verify that the property exists. error at $RDCManFile.Configuration.AppendChild($Child).
If I can accept a .rdg file format and structure as defined in the Script to create a Remote Desktop Connection Manager group from Active Directory Technet article then I'd use
$RDCManFile.RDCMan.file.AppendChild($Child)
Follow the Theo's answer about calling a function.
Pass parameters as positional
Add-NewGroup 'DCs' $XMLFile
or as named
Add-NewGroup -GroupName 'DCs' -RDCManFile $XMLFile
This error (and second) most likely means that $RDCManFile is null.
You cannot call a method on a null-valued expression.
At D:\Users\user\Desktop\Projects\RDCMan\Create-RDG.ps1:179 char:5
+ $Child = $RDCManFile.ImportNode($GroupXML.group, $true)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Try adding $RDCManFile | Out-Host at the top of the Add-NewGroup function to check what's contained in that variable.
You need to change the way you are calling the function.
Because of the comma in between the parameters, PowerShell sees this as one array value, so only parameter $GroupName will receive something.
Furthermore, you should not use brackets around the params, call the function like this:
Add-NewGroup 'DCs' $XMLFile
or send the parameters using their names:
Add-NewGroup -GroupName 'DCs' -RDCManFile $XMLFile

PowerShell error 'can't call null-value expresssion' [duplicate]

I am simply trying to create a powershell script which calculates the md5 sum of an executable (a file).
My .ps1 script:
$answer = Read-Host "File name and extension (ie; file.exe)"
$someFilePath = "C:\Users\xxx\Downloads\$answer"
If (Test-Path $someFilePath){
$stream = [System.IO.File]::Open("$someFilePath",[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
$hash = [System.BitConverter]::ToString($md5.ComputeHash($stream))
$hash
$stream.Close()
}
Else{
Write-Host "Sorry, file $answer doesn't seem to exist."
}
Upon running my script I receive the following error:
You cannot call a method on a null-valued expression.
At C:\Users\xxx\Downloads\md5sum.ps1:6 char:29
+ $hash = [System.BitConverter]::ToString($md5.Compute ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
To my understanding, this error means the script is attempting to do something, but another part of the script does not have any information to permit the first part of the script to work properly. In this case, $hash.
Get-ExecutionPolicy outputs Unrestricted.
What is causing this error?
What exactly is my null valued expression?
Any help is appreciated. I apologize if this is trivial and will continue my research.
References:
http://blogs.technet.com/b/heyscriptingguy/archive/2013/03/27/troubleshoot-the-invokemethodonnull-error-with-powershell.aspx
How to get an MD5 checksum in PowerShell
The simple answer for this one is that you have an undeclared (null) variable. In this case it is $md5. From the comment you put this needed to be declared elsewhere in your code
$md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
The error was because you are trying to execute a method that does not exist.
PS C:\Users\Matt> $md5 | gm
TypeName: System.Security.Cryptography.MD5CryptoServiceProvider
Name MemberType Definition
---- ---------- ----------
Clear Method void Clear()
ComputeHash Method byte[] ComputeHash(System.IO.Stream inputStream), byte[] ComputeHash(byte[] buffer), byte[] ComputeHash(byte[] buffer, int offset, ...
The .ComputeHash() of $md5.ComputeHash() was the null valued expression. Typing in gibberish would create the same effect.
PS C:\Users\Matt> $bagel.MakeMeABagel()
You cannot call a method on a null-valued expression.
At line:1 char:1
+ $bagel.MakeMeABagel()
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
PowerShell by default allows this to happen as defined its StrictMode
When Set-StrictMode is off, uninitialized variables (Version 1) are assumed to have a value of 0 (zero) or $Null, depending on type. References to non-existent properties return $Null, and the results of function syntax that is not valid vary with the error. Unnamed variables are not permitted.

How to pass a custom enum to a function in powershell

When defining a function, how can you reference a custom enum?
Here's what I'm trying:
Add-Type -TypeDefinition #"
namespace JB
{
public enum InternetZones
{
Computer
,LocalIntranet
,TrustedSites
,Internet
,RestrictedSites
}
}
"# -Language CSharpVersion3
function Get-InternetZoneLogonMode
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true)]
[JB.InterfaceZones]$zone
)
[string]$regpath = ("HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\{0}" -f [int]$zone)
$regpath
#...
#Get-PropertyValue
}
Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
But this gives the error:
Get-ZoneLogonMode : Unable to find type [JB.InterfaceZones]. Make sure that the assembly that contains this type is loaded.
At line:29 char:1
+ Get-ZoneLogonMode -zone [JB.InternetZones]::TrustedSites
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (JB.InterfaceZones:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
NB: I'm aware I could use ValidateSet for similar functionality; however that has the disadvantage of only having a name value; as opposed to allowing me to program using friendly names which are then mapped to ints in the background (I could write code for that; but enum seems more appropriate if possible).
I'm using Powershell v4, but ideally I'd like a PowerShell v2 compatible solution as most users are on that version by default.
Update
I've corrected the typo (thanks PetSerAl; well spotted).
[JB.InterfaceZones]$zone now changed to [JB.InternetZones]$zone.
Now I'm seeing error:
Get-InternetZoneLogonMode : Cannot process argument transformation on parameter 'zone'. Cannot convert value "[JB.InternetZones]::TrustedSites" to type
"JB.InternetZones". Error: "Unable to match the identifier name [JB.InternetZones]::TrustedSites to a valid enumerator name. Specify one of the following
enumerator names and try again: Computer, LocalIntranet, TrustedSites, Internet, RestrictedSites"
At line:80 char:33
+ Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-InternetZoneLogonMode], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Get-InternetZoneLogonMode
The ISE gave this one away to me but your attempted syntax was not completely incorrect. I was able to do this and get it to work.
Get-InternetZoneLogonMode -Zone ([JB.InternetZones]::TrustedSites)
Again, If you look at the highlighting you will see how I came to that conclusion.
Per comments by PetSerAl & CB:
Corrected typo in function definition
from [JB.InterfaceZones]$zone
to [JB.InternetZones]$zone
Changed function call
from Get-InternetZoneLogonMode -zone [JB.InternetZones]::TrustedSites
to Get-InternetZoneLogonMode -zone TrustedSites

Putting together an ADSI LDAP query

I am searching through the active directory for users under a specific organisation unit, that I would like to change using ADSI.
# get all users from the organizational unit
$accounts = Get-ADObject -filter 'objectClass -eq "user"' -SearchBase $dsn
# iterate over user objects
foreach ($account in $accounts) {
# unfortunately we have to use ADSI over the set-aduser cmdlet as we neeed to touch remote desktop attribues
$user = [ADSI]"LDAP://" + ($account.DistinguishedName).ToString()
# get logon name
$SamAccountName = $user.psbase.InvokeGet("SamAccountName")
# Profile Attributes
$user.psbase.InvokeSet("ProfilePath", "")
$user.psbase.InvokeSet("ScriptPath", "DIR\Logon.cmd")
$user.psbase.InvokeSet("HomeDrive", "H:")
$user.psbase.InvokeSet("HomeDirectory", "\\host\users$\${SamAccountName}")
# Remote Desktop Services Attributes
$user.psbase.InvokeSet("TerminalServicesProfilePath", "")
$user.psbase.InvokeSet("TerminalServicesHomeDirectory", "\\host\users$\${SamAccountName}")
$user.psbase.InvokeSet("TerminalServicesHomeDrive", "H:")
# Write attributes back to global catalog
$user.SetInfo()
}
This all works fine, until it comes to the $user = [ADSI]"LDAP://" + ($account.DistinguishedName).ToString() part.
Method invocation failed because [System.DirectoryServices.DirectoryEntry] does not contain a method named 'op_Addition'.
At \\tsclient\D\SourceCode\PowerShell\Set-ADUserAttributes.ps1:37 char:5
+ $user = [ADSI]"LDAP://" + ($account.DistinguishedName).ToString()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Exception calling "InvokeGet" with "1" argument(s): "Unspecified error
"
At \\tsclient\D\SourceCode\PowerShell\Set-ADUserAttributes.ps1:40 char:5
+ $SamAccountName = $user.psbase.InvokeGet("SamAccountName")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
It seems there is no query getting executed. However, $account.DistinguishedName contains the correct LDAP path (which I have tested manually).
So what am I doing wrong here?.
You're trying to append to an ADSI object by casting "LDAP://" as [ADSI] before you do the append.
Cat your strings first, then do the cast:
$user = [ADSI]("LDAP://" + $account.DistinguishedName)
The casting operation has higher precedence than the concatenation operation, so you need to do the concatenation in a subexpression, either like this:
[adsi]("LDAP://" + $account.DistinguishedName)
or like this:
[adsi]"LDAP://$($account.DistinguishedName)"
The distinguished name is automatically converted to a string here, so you don't need to manually call ToString().

Method Invocation failed system.string error

Morning,
I'm trying to use a CSV file with a list of users and automate the process to set an AD users extensionAttribute15 back to the "notset" value.
I use a similar code to populate the attribute, the CSV file consists of just two things, the users LAN ID and the value for the attribute.
Populating the field is not the problem, changing the values back to "not set" has been.
Here is the code I am using.
Import-module ActiveDirectory
Import-CSV "code.csv" | % {
$User = $_.cn
$user.Put(“extensionAttribute15”, #())
$user.SetInfo()
}
and here are the errors.
Method invocation failed because [System.String] doesn't contain a method named 'Put'.
At attribute.ps1:4 char:10
+ $user.Put <<<< (“extensionAttribute15”, #())
+ CategoryInfo : InvalidOperation: (Put:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Method invocation failed because [System.String] doesn't contain a method named 'SetInfo'.
At attribute.ps1:5 char:14
+ $user.SetInfo <<<< ()
+ CategoryInfo : InvalidOperation: (SetInfo:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Any ideas what the problem could be?
Thanks,
When you read in a CSV file, the resulting objects are just simple property bags. They don't support any special methods, they just hold flat data. There is nothing in these objects that isn't present in the text of the CSV file itself.
If you want to obtain a rich object which has Active Directory context and capabilities, you will need to obtain one from a cmdlet in the ActiveDirectory module.
Something like this is probably along the lines you need
Import-module ActiveDirectory
Import-CSV "code.csv" | % {
$user = Get-ADUser $_.cn # get a rich object from the AD module, by passing a string
$user.Put(“extensionAttribute15”, #())
$user.SetInfo()
}