New to Powershell - Here's what I have so far (1 Viewer)

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
Dipping my toe into the powershell arena. I know some basic programming (formal training in Pascal and QBasic) and what I've picked up of VBA from Excel and Access.

So, I can't say that I know any particular scripting language so I thought I would jump into powershell instead of learning something else. Anywho...

I'm trying to write a basic script to automate a directory structure and some other folders that we create for each major piece of equipment we fabricate. The basic steps could be broken down as:

1. Receive user input for Unit Number
2. Check if unit file already exists (cancel if true)
3. Create file structure.
4. Optional - Send e-mail to recipients informing them of directory creation.

Here's what I have so far (remember I'm very green to powershell)

Code:
Add- Type -AssemblyName Microsoft.VisualBasic
$title = 'Unit Number as XX-XXXX'
$msg = 'Enter the unit number for the unit file.'
$UnitNum = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)

$Path = "******"

New-Item -Path '$Path\$UnitNum' -ItemType Directory
New-Item -Path '$Path\$UnitNum\1 - CUSTOMER PROVIDED' -ItemType Directory
New-Item -PATH '$Path\$UnitNum\2 - ENGINEERING' -ItemType Directory
New-Item -PATH '$Path\$UnitNum\3 - PRODUCTION' -ItemType Directory
New-Item -PATH '$Path\$UnitNum\4 - PARTS' -ItemType Directory
New-Item -PATH '$Path\$UnitNum\5 - COMMUNICATION' -ItemType Directory
New-Item -PATH '$Path\$UnitNum\6 - PICTURES' -ItemType Directory

I haven't been able to find a good reference for creating a shortcut. Can someone direct me to one? I have two additional folders (not yet shown) that should be created in separate server locations with shortcuts to those locations placed in the main directory structure.
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
That's a great reference, thanks!
It turns out that what I really want is a symbolic link. The folder will appear to be in the directory structure but will actually be located in a separate structure with separate permissions. Interesting stuff I didn't even know that I could set up.
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
Well, I thought I had a start, but this doesn't actually do anything...LOL!

Any thoughts? Am I starting this correctly? I'm running the .ps1 file in powershell. Should I be calling the file differently?

Python:
Add-Type -AssemblyName Microsoft.VisualBasic
$title = 'Unit Number as XX-XXXX'
$msg = 'Enter the unit number for the unit file.'
$UnitNum = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title)

Try
{
    $Path = "******"
    $TestPath = $Path + $UnitNum

    #Check if either directory location already exists
    If ( -not (Test-Path -LiteralPath $TestPath -PathType Container)) -or ( -not (Test-Path -LiteralPath "\\KCI-Cambridge\Confidential\$UnitNum" -PathType Container))
    {
        #Create the main directory structure
        New-Item -Path $TestPath
        New-Item -Path "$TestPath\0 - CONFIDENTIAL" -ItemType Directory
        New-Item -Path "$TestPath\1 - CUSTOMER PROVIDED" -ItemType Directory
        New-Item -Path "$TestPath\2 - ENGINEERING" -ItemType Directory
        New-Item -Path "$TestPath\3 - PRODUCTION" -ItemType Directory
        New-Item -Path "$TestPath\4 - PARTS" -ItemType Directory
        New-Item -Path "$TestPath\5 - COMMUNICATION" -ItemType Directory
        New-Item -Path "$TestPath\6 - PICTURES" -ItemType Directory
        
        #Make Symbolic Link to confidential file location
        New-Item -Path "*****\$UnitNum" -ItemType Directory
        New-Item -Path "$TestPath\0 - CONFIDENTIAL" -ItemType SymbolicLink -Value \\KCI-Cambridge\Confidential
    }
    Else
    {
        #User message if directory exists
        Add- Type -AssemblyName Microsoft.VisualBasic
        $title = "SCRIPT ABORTED!"
        $msg = "The directory file location already exists."
        $Result = [Microsoft.VisualBasic.Interaction]::MsgBox($msg, OKOnly, $title)
        Exit
    }
}
Catch [System.UnauthorizedAcessException]
{
        #User message if access denied error
        Add- Type -AssemblyName Microsoft.VisualBasic
        $title = "ACCESS DENIED!"
        $msg = "You don't have permission to add this Unit File."
        $Result = [Microsoft.VisualBasic.Interaction]::MsgBox($msg, OKOnly, $title)
        Exit
}
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
So, how does powershell work. I'm launching my script within PS and getting errors. But, the cited errors occur after the first sections of code but I don't get any of the message box popups. Does PS "compile" or something like that on run and then execute? Here is the latest version of the script:

Python:
#Add visual basic classes for using inputbox and messagebox
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName PresentationFramework

Do
{
    #Receive unit number input from user
    $title = "Unit Number Input"
    $msg = "Enter the full 6 digit unit number"
    $value = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title, '')
   
    #Validate the user input
    If ($null -ne $value -and $value -match '\d\d-\d\d\d\d')
    {
        $GoodInput = True
    }
    Else
    {
        [System.Windows.MessageBox]::Show("Your unit number was in an invalid format.")
        $GoodInput = False
    }
}
Until {$GoodInput = True}

Try
{
    $Path = "*****"
    $TestPath = $Path + $UnitNum

    #Check if either directory location already exists
    If ( -not (Test-Path -LiteralPath $TestPath -PathType Container)) -or ( -not (Test-Path -LiteralPath "\\KCI-Cambridge\Confidential\$UnitNum" -PathType Container))
    {
        #Create the main directory structure
        New-Item -Path $TestPath
        New-Item -Path "$TestPath\0 - CONFIDENTIAL" -ItemType Directory
        New-Item -Path "$TestPath\1 - CUSTOMER PROVIDED" -ItemType Directory
        New-Item -Path "$TestPath\2 - ENGINEERING" -ItemType Directory
        New-Item -Path "$TestPath\3 - PRODUCTION" -ItemType Directory
        New-Item -Path "$TestPath\4 - PARTS" -ItemType Directory
        New-Item -Path "$TestPath\5 - COMMUNICATION" -ItemType Directory
        New-Item -Path "$TestPath\6 - PICTURES" -ItemType Directory
       
        #Make Symbolic Link to confidential file location
        New-Item -Path "*****\$UnitNum" -ItemType Directory
        New-Item -Path "$TestPath\0 - CONFIDENTIAL" -ItemType SymbolicLink -Value \\KCI-Cambridge\Confidential
    }
    Else
    {
        #User message if directory exists
        [System.Windows.MessageBox]::Show("The specified unit file already exist.  Script aborting.")
        Exit
    }
}
Catch [System.UnauthorizedAcessException]
{
    #User message if access denied error
    [System.Windows.MessageBox]::Show("You don't have permission to add this unit file.  Script aborting.")
    Exit
}
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
@theDBguy and anyone else,

Ok.....almost there.....
Here is the latest script. Everything seems to work EXCEPT for creating the symbolic link (I am testing this in PS with admin). I've tried a few different formats based on MS documentation and sample snippets from other websites. Can't get it to work.

Python:
New-Item -ItemType SymbolicLink -Path $LinkPath -Target $ConfPath

Here's the full script:
Python:
#Add visual basic classes for using inputbox and messagebox
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName PresentationFramework

[System.Windows.MessageBox]::Show("Test message.")

Do
{
    #Receive unit number input from user
    $title = "Unit Number Input"
    $msg = "Enter the full 6 digit unit number"
    $value = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title, '')
    
    #Validate the user input
    If ($null -ne $value -and $value -match '\d\d-\d\d\d\d')
    {
        $GoodInput = $True
    }
    Else
    {
        [System.Windows.MessageBox]::Show("Your unit number was in an invalid format.")
        $GoodInput = $False
    }
}
Until ($GoodInput = $True)

Try
{
    $Path = "*****"
    $TestPath = $Path + $value
    $TestPath

    #Check if either directory location already exists
    $criteria1 = Test-Path -LiteralPath $TestPath -PathType Container
    $criteria1
    $ConfPath = "*****" + $value
    $ConfPath
    $criteria2 = Test-Path -LiteralPath $ConfPath -PathType Container
    $criteria2
    If (-not ($criteria1) -and -not ($criteria2))
    {
        #Create the main directory structure
        New-Item -Path $TestPath -ItemType Directory
        New-Item -Path "$TestPath\0 - CONFIDENTIAL" -ItemType Directory
        New-Item -Path "$TestPath\1 - CUSTOMER PROVIDED" -ItemType Directory
        New-Item -Path "$TestPath\2 - ENGINEERING" -ItemType Directory
        New-Item -Path "$TestPath\3 - PRODUCTION" -ItemType Directory
        New-Item -Path "$TestPath\4 - PARTS" -ItemType Directory
        New-Item -Path "$TestPath\5 - COMMUNICATION" -ItemType Directory
        New-Item -Path "$TestPath\6 - PICTURES" -ItemType Directory
        
        #Make Symbolic Link to confidential file location
        $LinkPath = "$TestPath\0 - CONFIDENTIAL"
        $LinkPath
        New-Item -Path $ConfPath -ItemType Directory
        New-Item -ItemType SymbolicLink -Path $LinkPath -Target $ConfPath
    }
    Else
    {
        #User message if directory exists
        [System.Windows.MessageBox]::Show("The specified unit file already exist.  Script aborting.")
        Exit
    }
}
Catch [System.UnauthorizedAcessException]
{
    #User message if access denied error
    [System.Windows.MessageBox]::Show("You don't have permission to add this unit file.  Script aborting.")
    Exit
}
 

theDBguy

I’m here to help
Staff member
Local time
Yesterday, 21:42
Joined
Oct 29, 2018
Messages
16,572
@theDBguy and anyone else,

Ok.....almost there.....
Here is the latest script. Everything seems to work EXCEPT for creating the symbolic link (I am testing this in PS with admin). I've tried a few different formats based on MS documentation and sample snippets from other websites. Can't get it to work.

Python:
New-Item -ItemType SymbolicLink -Path $LinkPath -Target $ConfPath

Here's the full script:
Python:
#Add visual basic classes for using inputbox and messagebox
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName PresentationFramework

[System.Windows.MessageBox]::Show("Test message.")

Do
{
    #Receive unit number input from user
    $title = "Unit Number Input"
    $msg = "Enter the full 6 digit unit number"
    $value = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title, '')
   
    #Validate the user input
    If ($null -ne $value -and $value -match '\d\d-\d\d\d\d')
    {
        $GoodInput = $True
    }
    Else
    {
        [System.Windows.MessageBox]::Show("Your unit number was in an invalid format.")
        $GoodInput = $False
    }
}
Until ($GoodInput = $True)

Try
{
    $Path = "*****"
    $TestPath = $Path + $value
    $TestPath

    #Check if either directory location already exists
    $criteria1 = Test-Path -LiteralPath $TestPath -PathType Container
    $criteria1
    $ConfPath = "*****" + $value
    $ConfPath
    $criteria2 = Test-Path -LiteralPath $ConfPath -PathType Container
    $criteria2
    If (-not ($criteria1) -and -not ($criteria2))
    {
        #Create the main directory structure
        New-Item -Path $TestPath -ItemType Directory
        New-Item -Path "$TestPath\0 - CONFIDENTIAL" -ItemType Directory
        New-Item -Path "$TestPath\1 - CUSTOMER PROVIDED" -ItemType Directory
        New-Item -Path "$TestPath\2 - ENGINEERING" -ItemType Directory
        New-Item -Path "$TestPath\3 - PRODUCTION" -ItemType Directory
        New-Item -Path "$TestPath\4 - PARTS" -ItemType Directory
        New-Item -Path "$TestPath\5 - COMMUNICATION" -ItemType Directory
        New-Item -Path "$TestPath\6 - PICTURES" -ItemType Directory
       
        #Make Symbolic Link to confidential file location
        $LinkPath = "$TestPath\0 - CONFIDENTIAL"
        $LinkPath
        New-Item -Path $ConfPath -ItemType Directory
        New-Item -ItemType SymbolicLink -Path $LinkPath -Target $ConfPath
    }
    Else
    {
        #User message if directory exists
        [System.Windows.MessageBox]::Show("The specified unit file already exist.  Script aborting.")
        Exit
    }
}
Catch [System.UnauthorizedAcessException]
{
    #User message if access denied error
    [System.Windows.MessageBox]::Show("You don't have permission to add this unit file.  Script aborting.")
    Exit
}
Hi. Just FYI, I don't have admin rights at work, so I can't run/test your script until I get home. Keep up the good work!
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
I saw a thread where the error I get (which is a terribly unhelpful error report) can be caused by trying to create a sym link where one already exists. So, I'm trying to see how I can view existing sym links. I placed a dummy text file in the target location and the link isn't active anyway. Or its all a red herring and some OTHER issue. *sigh*
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
I checked for existing sym links (I had been testing this script for awhile and thought maybe it had been creating them this whole time), but it did not find any.

One issue has been resolved. I thought I had a higher version of PS installed, but I currently have PS 5.1. So, I did some specific googling on the New-Item cmdlet in 5.1 regarding symlinks and found you have to specify the link name. So the new command is:

Python:
New-Item -Path $LocationPath -ItemType SymbolicLink  -Name $LinkName -Target $TargetPath

So, the error has now shifted from an IO error to a Type Error. Windows is calling a System.UnauthorizedAccessException and it COULD be permission related as PS 5.1 requires admin permission for symbolic links. But, PS is running as admin currently and I am authenticated as a local admin. Plus, developer mode is enabled.

This is the last piece. Any thoughts? Here's the full error return from powershell:

Code:
Unable to find type [System.UnauthorizedAcessException].
At C:\UnitBookCreationScript.ps1:65 char:7
+ Catch [System.UnauthorizedAcessException]
+       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.UnauthorizedAcessException:TypeName) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound

Further bit of potentially useful information - the target link is to a folder with limited permisions for most. However, my user should have full permissions and I have created files in that directory without a problem.
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
Ok. Well, I "kind of" sorted the problem. It occurred to me that these locations are on our file server which I DON'T have admin rights to (though I do have full regular privileges). Once I did a test with a local directory it worked without error. Now, I have to figure out if there's any way to make this work on the server.
 

theDBguy

I’m here to help
Staff member
Local time
Yesterday, 21:42
Joined
Oct 29, 2018
Messages
16,572
Ok. Well, I "kind of" sorted the problem. It occurred to me that these locations are on our file server which I DON'T have admin rights to (though I do have full regular privileges). Once I did a test with a local directory it worked without error. Now, I have to figure out if there's any way to make this work on the server.
Hi. Glad to hear you got it sorted out. Some PS cmdlets require admin rights (even though you can do them manually without admin rights - as long as you don't use PS). If you don't have it, not sure you can use PS at all.
 
Last edited:

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
Well, Symlinks wasn't necessarily needed anyway. I convinced myself they were "better" than Windows shortcuts. In practical terms, they function similarly and Symlinks are really designed to faciliate cross-compatabilty with Unix NFTS systems. So, I redid the script with shortcut instead (which ironically requires calling VBscript modules to make it work..ha!) and voila!

Python:
#Add visual basic classes for using inputbox and messagebox
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName PresentationFramework

Do
{
    #Receive unit number input from user
    $title = "Unit Number Input"
    $msg = "Enter the full 6 digit unit number"
    $value = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title, '')
    
    #Validate the user input
    If ($null -ne $value -and $value -match '\d\d-\d\d\d\d')
    {
        $GoodInput = $True
    }
    Else
    {
        [System.Windows.MessageBox]::Show("Your unit number was in an invalid format.")
        $GoodInput = $False
    }
}
Until ($GoodInput = $True)

Try
{
    $Path = "*****"
    $TestPath = $Path + $value

    #Check if either directory location already exists
    $criteria1 = Test-Path -LiteralPath $TestPath -PathType Container
    $ConfPath = "*****" + $value
    $criteria2 = Test-Path -LiteralPath $ConfPath -PathType Container
    If (-not ($criteria1) -and -not ($criteria2))
    {
        #Create the main directory structure
        New-Item -Path $TestPath -ItemType Directory
        New-Item -Path "$TestPath\1 - CUSTOMER PROVIDED" -ItemType Directory
        New-Item -Path "$TestPath\2 - ENGINEERING" -ItemType Directory
        New-Item -Path "$TestPath\3 - PRODUCTION" -ItemType Directory
        New-Item -Path "$TestPath\4 - PARTS" -ItemType Directory
        New-Item -Path "$TestPath\5 - COMMUNICATION" -ItemType Directory
        New-Item -Path "$TestPath\6 - PICTURES" -ItemType Directory
        
        #Create confidential file location and shortcut to it
        New-Item -Path $ConfPath -ItemType Directory
        $TargetLoc = $ConfPath + "\"
        $ShortcutLoc = $TestPath + "\"
        $ShortcutName = "0 - CONFIDENTIAL"
        $ShortcutFile = $ShortcutLoc + $ShortcutName + ".lnk"
        $WscriptShell = New-Object -ComObject Wscript.Shell
        $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
        $Shortcut.TargetPath = $TargetLoc
        $Shortcut.Save()
        #Symbolic Link does not work without admin permissions on the server
        
    }
    Else
    {
        #User message if directory exists
        [System.Windows.MessageBox]::Show("The specified unit file already exist.  Script aborting.")
        Exit
    }
}
Catch [System.UnauthorizedAccessException]
{
    #User message if access denied error
    [System.Windows.MessageBox]::Show("You don't have permission to add this unit file.  Script aborting.")
    Exit
}
 

theDBguy

I’m here to help
Staff member
Local time
Yesterday, 21:42
Joined
Oct 29, 2018
Messages
16,572
Well, Symlinks wasn't necessarily needed anyway. I convinced myself they were "better" than Windows shortcuts. In practical terms, they function similarly and Symlinks are really designed to faciliate cross-compatabilty with Unix NFTS systems. So, I redid the script with shortcut instead (which ironically requires calling VBscript modules to make it work..ha!) and voila!

Python:
#Add visual basic classes for using inputbox and messagebox
Add-Type -AssemblyName Microsoft.VisualBasic
Add-Type -AssemblyName PresentationFramework

Do
{
    #Receive unit number input from user
    $title = "Unit Number Input"
    $msg = "Enter the full 6 digit unit number"
    $value = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title, '')
   
    #Validate the user input
    If ($null -ne $value -and $value -match '\d\d-\d\d\d\d')
    {
        $GoodInput = $True
    }
    Else
    {
        [System.Windows.MessageBox]::Show("Your unit number was in an invalid format.")
        $GoodInput = $False
    }
}
Until ($GoodInput = $True)

Try
{
    $Path = "*****"
    $TestPath = $Path + $value

    #Check if either directory location already exists
    $criteria1 = Test-Path -LiteralPath $TestPath -PathType Container
    $ConfPath = "*****" + $value
    $criteria2 = Test-Path -LiteralPath $ConfPath -PathType Container
    If (-not ($criteria1) -and -not ($criteria2))
    {
        #Create the main directory structure
        New-Item -Path $TestPath -ItemType Directory
        New-Item -Path "$TestPath\1 - CUSTOMER PROVIDED" -ItemType Directory
        New-Item -Path "$TestPath\2 - ENGINEERING" -ItemType Directory
        New-Item -Path "$TestPath\3 - PRODUCTION" -ItemType Directory
        New-Item -Path "$TestPath\4 - PARTS" -ItemType Directory
        New-Item -Path "$TestPath\5 - COMMUNICATION" -ItemType Directory
        New-Item -Path "$TestPath\6 - PICTURES" -ItemType Directory
       
        #Create confidential file location and shortcut to it
        New-Item -Path $ConfPath -ItemType Directory
        $TargetLoc = $ConfPath + "\"
        $ShortcutLoc = $TestPath + "\"
        $ShortcutName = "0 - CONFIDENTIAL"
        $ShortcutFile = $ShortcutLoc + $ShortcutName + ".lnk"
        $WscriptShell = New-Object -ComObject Wscript.Shell
        $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
        $Shortcut.TargetPath = $TargetLoc
        $Shortcut.Save()
        #Symbolic Link does not work without admin permissions on the server
       
    }
    Else
    {
        #User message if directory exists
        [System.Windows.MessageBox]::Show("The specified unit file already exist.  Script aborting.")
        Exit
    }
}
Catch [System.UnauthorizedAccessException]
{
    #User message if access denied error
    [System.Windows.MessageBox]::Show("You don't have permission to add this unit file.  Script aborting.")
    Exit
}
Congratulations!
 

Isaac

Lifelong Learner
Local time
Yesterday, 21:42
Joined
Mar 14, 2017
Messages
5,768
Well, this thread has given me some more clarity in the "powershell vs. vbscript" subject. I can't say I learned a lot, but got some ideas about how universally use-able PS is, or isn't, compared to VBS. Thanks for sharing your experiences, J, it's fascinating to see PS code - quite succinct, at times, which is cool. Almost like..."generation 5" (or whatever the biggest number is nowadays). Like the creator of PS has essentially pre-compiled some very "complete" topics into single commands.
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
@Isaac - Thanks everyone!

Glad everyone found it useful. It probably would have gone quicker with a proper dev environment rather than just running the script and seeing what errors I received. I was using Notepad++ but could have used some catches on basic syntax. I did pick up the syntax fairly quickly. It does have some robust cmdlets. You can actually write your own cmdlets as I understand it, which is kind of cool. There's even a shorthand that obviously makes reading harder but shortens up commands and lines even more.

Plus the whole symbolic link thing was a giant boondoggle between different PS versions and different feelings of MS on who should or shouldn't create them. I guess Windows (due primarily to its long legacy support) is weak to a particular type of attack using Symlinks so the only way to adequately mitigate that attack surface was to elevate the permissions for viewing (and thus creating) SymLinks.

Ironically, powershell is the newbie (relatively speaking) annoying TWO groups of veterans. It's "replacing" VBscript and it's userbase. It's also "replacing" DOS CMD shell and a subset of Windows Power Users/Admins and their custom Windows apps they know and love. I give it kudos just for being willing to take on both groups! :)

MS could still use someone who know how to write a decent support document. Since its PS over VBA it is definitely more complete, but their examples are STILL lacking in clarity at times. It was a fun little project and I'm glad it works!
 

theDBguy

I’m here to help
Staff member
Local time
Yesterday, 21:42
Joined
Oct 29, 2018
Messages
16,572

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
I think they're called Functions.
It's a little more involved. Here are a couple of posts from Stack Overflow.

A cmdlet is a .NET class written in C# or other .NET language and contained in a .dll (i.e. in a binary module). A function is specified directly in PowerShell in a script, script module or at the command line. A module manifest may include both script and binary modules so the manifest needs to be able to export both cmdlets and functions. It's even possible to have both a cmdlet and a function with the same name exported from a single manifest though that's generally not recommended.

To complement Bruce Payette's helpful answer:

Not all functions are created equal in PowerShell:
  • An advanced function is the written-in-PowerShell analog of a (binary) cmdlet (which, as stated, is compiled from a .NET language); decorating a function's param(...) block with the [CmdletBinding()] attribute or decorating at least one parameter with a [Parameter()] attribute thanks, Ansgar Wiechers is what makes it an advanced one; as such, it supports certain standard behaviors:
    • You gain automatic support for common parameters such as -Verbose, and -OutVariable and, on an opt-in basis, for -WhatIf and -Confirm.
    • Arguments that cannot be bound to explicitly declared parameters result in an error on invocation.
    • Typically, but not necessarily, advanced functions support one-by-one pipeline-input processing via a process { ... } script block, via parameter-binding parameters decorated with ValueFromPipeline and/or ValueFromPipelineByPropertyName.
    • Unfortunately, even advanced functions and cmdlets aren't created fully equal:
      • Advanced functions run in a child variable scope, unlike cmdlets.
        • However, it is possible to gain access to the caller's variables even in functions placed in modules (to functions outside of modules the caller's variables are visible by default, owing to PowerShell's dynamic scoping), via the $PSCmdlet.SessionState.PSVariable object, as shown in this answer.
      • Advanced functions apply culture-invariant parameter conversions, unlike cmdlets.
      • Advanced functions, in Windows PowerShell, handle ValueFromRemainingArguments differently than cmdlets.
        • This inconsistency was resolved in PowerShell Core, but, unfortunately, in a manner that created more problems than it solved - see GitHub issues #5955 and #6451.
  • A simple function, by contrast:
    • is appropriate for script- and module-internal helper functions
    • requires less "ceremony" (simpler syntax without parameter attributes, single-script-block body)
    • can, however, still process pipeline input via automatic variable $Input or even via a process { ... } block, if desired.
    • also runs in a child scope by default; outside of modules (which simple function shouldn't be exported from anyway), the caller's variables are visible owing to PowerShell's dynamic scoping; modifying them (which should generally be avoided) requires calls to Set-Variable with -Scope 1.
    • Note that there's also a specialized, but rarely used variant of a simple function optimized for pipeline processing, defined with the Filter keyword. Its body is implicitly invoked for each pipeline input object, reflected in automatic variable $_.
While exporting functions as part of a module - preferably via its module manifest (*.psd1) - doesn't enforce that functions are advanced ones, it is good practice to only exported advanced functions.
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
So, I messed up my function code...anyone have insight on using parameters? Here's the code:

Python:
#Define Shortcut Function
function jmMakeShortcut {
    Param($LinkLoc, $LinkTarget, $LinkName)
    $WscriptShell = New-Object -ComObject Wscript.Shell
    $ShortcutFile = $LinkLoc + $LinkName + ".lnk"
    $ShortcutFile
    $Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)
    $Shortcut.TargetPath = $LinkTarget
    $Shortcut.Save()
}
 

JMongi

Active member
Local time
Today, 00:42
Joined
Jan 6, 2021
Messages
625
Ok, So it's not my parameters. If I pass in the parameters and then print them, I get the right ones.
For some reason my string concatenation (which worked in the code posted in #12) is not working in this function. I'm at a loss.
Here is what I get printing the three parameters after they've been passed to the function and then the concatenated string (with redactions) $ShortcutFile
$LinkTarget = \\*****\Confidential\77-7777\
$LinkLoc = \\*****\Kingsly Master Files\1 - UNIT Files\77-7777\
$LinkName = 9 - CONFIDENTIAL
$ShortcutFile = \\*****\KingslyMasterFiles\1 - UNIT Files\77-7777\ \\*****\Confidential\77-7777\ 9 - CONFIDENTIAL + + .lnk

So, I have to be doing the concatenation wrong.
 

Users who are viewing this thread

Top Bottom