Pablo's Powershell Pow-Wow

Discussion in 'Business & Enterprise Computing' started by PabloEscobar, Sep 18, 2014.

  1. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    Not specifically related to your query, but may also be helpful...

    Code:
    
    $file = "C:\temp\banana.csv"
    $file | Split-Path -Leaf
    
    
    Output is simply "banana.csv"
     
  2. mr626

    mr626 Member

    Joined:
    Jul 17, 2011
    Messages:
    2,758
    Hi guys,

    Apologies if this isn't the best place to ask (I'll ask a mod to move it if so), but I'm stuck on a powershell issue. I seem to be hitting some string length threshold or something, but I'm a bit confused.

    I'm creating a 'kiosk' Windows 10 machine using the info from this page:

    https://technet.microsoft.com/en-au...p-a-kiosk-for-windows-10-for-desktop-editions

    Specifically, using this Powershell:

    Code:
    # Check if shell launcher license is enabled
    function Check-ShellLauncherLicenseEnabled
    {
        [string]$source = @"
    using System;
    using System.Runtime.InteropServices;
    
    static class CheckShellLauncherLicense
    {
        const int S_OK = 0;
    
        public static bool IsShellLauncherLicenseEnabled()
        {
            int enabled = 0;
    
            if (NativeMethods.SLGetWindowsInformationDWORD("EmbeddedFeature-ShellLauncher-Enabled", out enabled) != S_OK) {
                enabled = 0;
            }
    
            return (enabled != 0);
        }
    
        static class NativeMethods
        {
            [DllImport("Slc.dll")]
            internal static extern int SLGetWindowsInformationDWORD([MarshalAs(UnmanagedType.LPWStr)]string valueName, out int value);
        }
    
    }
    "@
    
        $type = Add-Type -TypeDefinition $source -PassThru
    
        return $type[0]::IsShellLauncherLicenseEnabled()
    }
    
    [bool]$result = $false
    
    $result = Check-ShellLauncherLicenseEnabled
    "`nShell Launcher license enabled is set to " + $result
    if (-not($result))
    {
        "`nThis device doesn't have required license to use Shell Launcher"
        exit
    }
    
    $COMPUTER = "localhost"
    $NAMESPACE = "root\standardcimv2\embedded"
    
    # Create a handle to the class instance so we can call the static methods.
    try {
        $ShellLauncherClass = [wmiclass]"\\$COMPUTER\${NAMESPACE}:WESL_UserSetting"
        } catch [Exception] {
        write-host $_.Exception.Message; 
        write-host "Make sure Shell Launcher feature is enabled"
        exit
        }
    
    
    # This well-known security identifier (SID) corresponds to the BUILTIN\Administrators group.
    
    $Admins_SID = "S-1-5-32-544"
    
    # Create a function to retrieve the SID for a user account on a machine.
    
    function Get-UsernameSID($AccountName) {
    
        $NTUserObject = New-Object System.Security.Principal.NTAccount($AccountName)
        $NTUserSID = $NTUserObject.Translate([System.Security.Principal.SecurityIdentifier])
    
        return $NTUserSID.Value
    
    }
    
    # Get the SID for a user account named "Cashier". Rename "Cashier" to an existing account on your system to test this script.
    
    $Cashier_SID = Get-UsernameSID("Cashier")
    
    # Define actions to take when the shell program exits.
    
    $restart_shell = 0
    $restart_device = 1
    $shutdown_device = 2
    
    # Examples. You can change these examples to use the program that you want to use as the shell.
    
    # This example sets the command prompt as the default shell, and restarts the device if the command prompt is closed. 
    
    $ShellLauncherClass.SetDefaultShell("cmd.exe", $restart_device)
    
    # Display the default shell to verify that it was added correctly.
    
    $DefaultShellObject = $ShellLauncherClass.GetDefaultShell()
    
    "`nDefault Shell is set to " + $DefaultShellObject.Shell + " and the default action is set to " + $DefaultShellObject.defaultaction
    
    # Set Internet Explorer as the shell for "Cashier", and restart the machine if Internet Explorer is closed.
    
    $ShellLauncherClass.SetCustomShell($Cashier_SID, "c:\program files\internet explorer\iexplore.exe www.microsoft.com", ($null), ($null), $restart_shell)
    
    # Set Explorer as the shell for administrators.
    
    $ShellLauncherClass.SetCustomShell($Admins_SID, "explorer.exe")
    
    # View all the custom shells defined.
    
    "`nCurrent settings for custom shells:"
    Get-WmiObject -namespace $NAMESPACE -computer $COMPUTER -class WESL_UserSetting | Select Sid, Shell, DefaultAction
    
    # Enable Shell Launcher
    
    $ShellLauncherClass.SetEnabled($TRUE)
    
    $IsShellLauncherEnabled = $ShellLauncherClass.IsEnabled()
    
    "`nEnabled is set to " + $IsShellLauncherEnabled.Enabled
    
    # Remove the new custom shells.
    
    $ShellLauncherClass.RemoveCustomShell($Admins_SID)
    
    $ShellLauncherClass.RemoveCustomShell($Cashier_SID)
    
    # Disable Shell Launcher
    
    $ShellLauncherClass.SetEnabled($FALSE)
    
    $IsShellLauncherEnabled = $ShellLauncherClass.IsEnabled()
    
    "`nEnabled is set to " + $IsShellLauncherEnabled.Enabled
    The only real difference with my script is that I'm opening a few websites rather than just the one- ie my code looks more like:

    Code:
    $ShellLauncherClass.SetCustomShell($Cashier_SID, "c:\program files\internet explorer\iexplore.exe www.microsoft.com apple.com slashdot.org reddit.com", ($null), ($null), $restart_shell)
    Everything works perfectly...UNTIL I go over a certain number of characters for the 'shell' agrument (the "c:\program files\internet explorer\iexplore.exe www.microsoft.com apple.com slashdot.org reddit.com" bit). I'm still working out the exact number of characters that is the threshold.

    When I hit that threshold, the script no longer works and powershell spits this out:

    Code:
    Get-WmiObject : Generic failure 
    At C:\Users\Administrator\Desktop\set_shell.ps1:54 char:1
    + Get-WmiObject -namespace $NAMESPACE -computer $COMPUTER -class WESL_U ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException
        + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
    I'm still working through some WMI debugging myself, but am I missing something super obvious?

    Thanks
     
  3. EvilGenius

    EvilGenius Member

    Joined:
    Apr 26, 2005
    Messages:
    10,845
    Location:
    elsewhere
    Sorry don't know the right coding for it, but can you add the list of sites to a .txt file or .csv, create a variable and call them from that instead of listing them out?
     
  4. mr626

    mr626 Member

    Joined:
    Jul 17, 2011
    Messages:
    2,758
    Tried adding the sites to a variable and calling that, but no dice.

    Thanks for the thought though
     
  5. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    Have you worked out what the maximum length you can use before it starts to fail?

    You could use $env:programfiles to reduce the path length of iexplore.exe however as that equates to the same thing, perhaps that will not help at all.

    Alternatively you could consider appending IEs directory to your PATH environmental variable and then just calling iexplore.exe.

    Lastly, I've done some reading up on the whole thing, but couldn't find what I was looking for, is it possible to just run multiple shells?

    e.g.
    Code:
    foreach ($website in $websites)
    {
         $ShellLauncherClass.SetCustomShell($Cashier_SID, "c:\program files\internet explorer\iexplore.exe $website", ($null), ($null), $restart_shell)
    }
    
     
  6. mr626

    mr626 Member

    Joined:
    Jul 17, 2011
    Messages:
    2,758
    Good thoughts, but have already tried using environmental variables to shorten things. As you suspected, once the variables are expanded it amounts to the same thing and still fails.

    Not sure how multiple shells would go- might not play nice with the kiosk machine being able to respond to the shell being closed.
     
  7. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,621
    It's a bit of a workaround, but we setup our environment using Group Policy Preferences registry settings for home pages and other tabs on launch... you could do similar with powershell, and pre-configure IE Registry settings, before launching it as the shell, that way, you don't need to pass them in as arguments to iexplore at all.

    Code:
    $Homepage = "http://www.test.com"
    $OtherPages = "http://www.example.com","http://www.cheese.com","http://sometimesredsometimesblue.com"
    $RegistryBollocks = "HKCU:\Software\Microsoft\Internet Explorer\Main"
    
    Set-ItemProperty $RegistryBollocks -name "Start Page" -value $Homepage
    Set-ItemProperty $RegistryBollocks -name "Secondary Start Pages" -value $OtherPages 
    
     
  8. mr626

    mr626 Member

    Joined:
    Jul 17, 2011
    Messages:
    2,758
    Nice :thumbup: I think I'll give that a shot. Thanks for the tip, and sorry for the threadcrap.
     
  9. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    Definitely not a threadcrap, t'was an interesting issue and I particularly like Pablo's workaround. :thumbup:
     
  10. Punk

    Punk Member

    Joined:
    Mar 15, 2002
    Messages:
    1,058
    Location:
    Walking on Sunshine
    Hi Guys,

    I would love some input into something I am working on as I am only a newbie at PowerShell.

    What I am trying to accomplish is that I will have a script that runs and removes permissions and Inheritance from all files created under a certain folder for that day. (Maybe many folders deep)

    This is what I have so far and it seems to work. I am worried about it scaling.
    Take note that I am using the following module too.
    https://gallery.technet.microsoft.com/scriptcenter/1abd77a5-9c0b-4a2b-acef-90dbb2b84e85

    Code:
    #Set Stuff
    $path = 'Q:\Test\'
    $account = 'Domain\Domain Users'
    
    #Stuff Happens
    
    $NewFiles = Get-ChildItem $path -Recurse -Attributes !D | Where { $_.LastWriteTime -ge [datetime]::Now.AddMinutes(-1440) } 
    
    $NewFiles | Disable-NTFSAccessInheritance
    
    $NewFiles | Remove-NTFSAccess -Account $account -AccessRights Modify
    
    $NewFiles | Add-NTFSAccess -Account $account -AccessRights ReadAndExecute
    I am open to otherways of completing the task :)
     
  11. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    I'm intrigued and I'd like to have a better look another day, but it is Friday afternoon and I'm about to go on a five day break so that'll have to wait...

    What I'm really interested in is how does this happen that you have to fix it via a script?

    Couldn't you prevent whatever/whomever is creating these files/folders with these permissions during creation rather than after the fact?
     
    Last edited: Nov 25, 2016
  12. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,621
    Whats the Goal? what ACL should your files and folders end up with?
     
  13. Punk

    Punk Member

    Joined:
    Mar 15, 2002
    Messages:
    1,058
    Location:
    Walking on Sunshine
    They want to "Lock" files from the end users once they have been "Finalized"

    Well the Security Group needs to move from Read/Write to ReadOnly and we only need to change the permissions on the file.

    The Goal is to have the files locked from end user changes but still readable. I think the ultimate goal is to be able to lock the files when ever they want by naming the folder a certain way. I.E "lockwhat ever folder is called"

    I am also trying to work out the best way for the logging of this job too.
     
  14. Dre_

    Dre_ Member

    Joined:
    May 25, 2014
    Messages:
    841
    Here is a quick question.
    I'm running Get-AzureRmVM and if I run it on its own I get a different output to when it runs after something.

    When I run

    Select-AzureRmSubscription -SubscriptionId $SubId
    Get-AzureRmVm

    I get

    Code:
    ResourceGroupName        : UPLOADER
    Id                       : /subscriptions/GUID/resourceGroups/UPLOADER/providers/Microsoft.Compute/virtualMachines/Uploader
    Name                     : Uploader
    Type                     : Microsoft.Rest.Azure.AzureOperationResponse`1[Microsoft.Rest.Azure.IPage`1[Microsoft.Azure.Management.Compute.Models.VirtualMachine]]
    Location                 : australiasoutheast
    LicenseType              : 
    Tags                     : {}
    AvailabilitySetReference : 
    DiagnosticsProfile       : Microsoft.Azure.Management.Compute.Models.DiagnosticsProfile
    Extensions               : {, }
    HardwareProfile          : Microsoft.Azure.Management.Compute.Models.HardwareProfile
    InstanceView             : 
    NetworkProfile           : Microsoft.Azure.Management.Compute.Models.NetworkProfile
    OSProfile                : Microsoft.Azure.Management.Compute.Models.OSProfile
    Plan                     : 
    ProvisioningState        : Succeeded
    StorageProfile           : Microsoft.Azure.Management.Compute.Models.StorageProfile
    DataDiskNames            : {}
    NetworkInterfaceIDs      : {/subscriptions/GUID/resourceGroups/Uploader/providers/Microsoft.Network/networkInterfaces/uploader315}
    RequestId                : GUID
    StatusCode               : OK
    But when I run just

    Get-AzureRmVm

    This is the output

    Code:
    RequestId                  : GUID
    StatusCode                 : OK
    ResourceGroupName          : UPLOADER
    Id                         : /subscriptions/GUID/resourceGroups/UPLOADER/providers/Microsoft.Compute/virtualMachines/Uploader
    Name                       : Uploader
    Type                       : Microsoft.Rest.Azure.AzureOperationResponse`1[Microsoft.Rest.Azure.IPage`1[Microsoft.Azure.Management.Compute.Models.VirtualMachine]]
    Location                   : australiasoutheast
    Tags                       : {}
    DiagnosticsProfile         : 
      BootDiagnostics          : 
        Enabled                : True
        StorageUri             : URI
    Extensions[0]              : 
      Id                       : /subscriptions/GUID/resourceGroups/UPLOADER/providers/Microsoft.Compute/virtualMachines/Uploader/extensions/enablevmaccess
    Extensions[1]              : 
      Id                       : /subscriptions/GUID/resourceGroups/UPLOADER/providers/Microsoft.Compute/virtualMachines/Uploader/extensions/Microsoft.Insights.VMDiagnosticsSettings
    HardwareProfile            : 
      VmSize                   : Standard_DS2_v2
    NetworkProfile             : 
      NetworkInterfaces[0]     : 
        Id                     : /subscriptions/GUID/resourceGroups/Uploader/providers/Microsoft.Network/networkInterfaces/uploader315
    OSProfile                  : 
      ComputerName             : Uploader
      AdminUsername            : User.name
      WindowsConfiguration     : 
        ProvisionVMAgent       : True
        EnableAutomaticUpdates : True
    ProvisioningState          : Succeeded
    StorageProfile             : 
      ImageReference           : 
        Publisher              : MicrosoftWindowsServer
        Offer                  : WindowsServer
        Sku                    : 2012-Datacenter
        Version                : latest
      OsDisk                   : 
        OsType                 : Windows
        Name                   : Uploader
        Vhd                    : 
          Uri                  : URI
        Caching                : ReadWrite
        CreateOption           : FromImage
    NetworkInterfaceIDs[0]     : /subscriptions/GUID/resourceGroups/Uploader/providers/Microsoft.Network/networkInterfaces/uploader315
    What gives?
     
    Last edited: Dec 3, 2016
  15. NSanity

    NSanity Member

    Joined:
    Mar 11, 2002
    Messages:
    18,393
    Location:
    Brisbane
    So I have a month left where I am, and not a whole bunch of work to do.

    Going to focus on my powershell, with particular attention to server 2012/2016, exchange, hyper-v, ad, dns, dhcp and other typical sysadmin-y stuff.

    Ordered a Learn Windows PowerShell in a Month of Lunches, Third Edition, bunch of ram and a scratch SSD for labbing - but I need somewhere to put my script work.

    I presume git w/ github - however if there is something better (particularly something i can keep private), I'm all ears. Not fussed if it costs me < $50/year.
     
  16. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,621
    SVN hosted locally works for me. YMMV.
     
  17. NSanity

    NSanity Member

    Joined:
    Mar 11, 2002
    Messages:
    18,393
    Location:
    Brisbane
    Nah, actually need something "cloud" so I can grab it from other places over HTTPS. Security is "somewhat" important - I'll endeavour not to put credentials etc in it, but want to be somewhat protected if they do end up there.

    Friend suggested bitbucket - I presume stitching that together w/ PSGet and POSH-Git will do the job?
     
    Last edited: Dec 5, 2016
  18. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    If you setup a free visual studio account you can use either Git or Team Foundation Version Control.

    It's especially handy if you actually use visual studio for PowerShell due to the Git integration.

    EDIT: Good breakdown of how to all works
     
  19. OP
    OP
    PabloEscobar

    PabloEscobar Member

    Joined:
    Jan 28, 2008
    Messages:
    14,621
    @Freaky - Do you use Visual Studio as an IDE for Powershell? How do you find it?
     
  20. freaky_beeky

    freaky_beeky Member

    Joined:
    Dec 2, 2004
    Messages:
    1,169
    Location:
    Brisbane
    I was for a short time, then I changed positions and have had to change back to PowerShellISE until Visual Studio gets through the internal software approval process.

    I really enjoyed configuring my own custom snippets and the git integration, but I didn't really get to use it long enough to really hit my stride.

    Using SourceTree (for git) and the ISE works for me otherwise.
     

Share This Page

Advertisement: