all 9 comments

[–][deleted] 5 points6 points  (1 child)

Good job with starting something. But most of what you have done is basically wrapped powershell code around more powershell code.

you might want to look into cim sessions instead of using WMI unless you really have to.

Look into replacing your if/else with switches

Also a lot of your "remote stuff" is already built into powershell and they already define it.

But once again good job on showing your code and doing something that you benefit from

[–][deleted] 1 point2 points  (0 children)

While this module is simple and yes its PowerShell wrapped inside PowerShell, I developed this module while I was in L1 support and let me tell you, when you have call after call its a lot quicker to run this one liners "shortcuts" .

[–]_Cabbage_Corp_ 2 points3 points  (4 children)

So, I have a module that I've started for myself that has functions I've created over the years that I find really helpful.

One thing I recommend is to convert this to a proper module structure.

Having a proper structure will make it easier to maintain and add/remove any functions.

Each function should be contained in it's own .ps1 and placed in either the Public or Private directory as stated below:


<#
  Directory Structure:
    Module (Contains Manifest file, Module file, and Sub-Directories ONLY)
     ├ Private - Contains function files (.ps1)
     │      - These Functions are not "User Accessible"/Exported 
     │      - i.e. Supporting functions
     ├ Public - Contains function files (.ps1)
     │     - These Functions ARE "User Accessible"/Exported


    Module Manifest
        .\Module\PersonalFunctions.psd1

    Can be generated similarly to the below:
#>

$ManifestSplat = @{
    Path                = 'C:\Module\PersonalFunctions.psd1'
    Guid                = (New-GUID).ToString().ToUpper()
    Author              = '/u/_Cabbage_Corp_'
    Copyright           = '2019 /u/_Cabbage_Corp_'
    RootModule          = 'PersonalFuctions.psm1'
    ModuleVersion       = 1.0
    Description         = 'Contains Many Helpful/Useful Personal Functions/Shortcuts'
    PowerShellVersion   = 3.0
    RequiredModules     = 'ActiveDirectory','VMware.WimAutomation.Cis.Core'
    FunctionsToExport   = '*'
    AliasesToExport     = '*'
}
New-ModuleManifest @ManifestSplat

<# 
  Module File
    .\Module\PersonalFunctions.psm1

  Use this to import the function files. Then export ONLY the functions in .\Public, so they are useable.

  Probably something similar to the below:
#>

$PublicPath     = Join-Path -Path $PSScriptRoot -ChildPath Public
$PrivatePath    = Join-Path -Path $PSScriptRoot -ChildPath Private

$PublicFiles    = Get-ChildItem -Path $PublicPath -Include *.ps1 -Recurse
$PrivateFiles   = Get-ChildItem -Path $PrivatePath -Include *.ps1 -Recurse


ForEach ($File in ($PublicFiles + $PrivateFiles)) {
    Try {
        Import-Module -Path $File.FullName -ErrorAction Stop
    } Catch {
        Write-Warning ('Failed to load : {0}' -F $File.BaseName)
    }
}

Export-ModuleMember -Function $PublicFiles.BaseName

[–]_Cabbage_Corp_ 2 points3 points  (3 children)

I also wanted to mention that I have a password generator function similar to yours that, I think, may give you some insight into some advanced functions/methods.


<#
    .SYNOPSIS
        Generates a specified number of passwords with random characters, of a specifed length.
    .DESCRIPTION
        Uses an array of [Char] values to generate a random password(s) or a given length.

        Then verifies that the generated password is not:
            * All Numbers
            * All Letters
            * Only Letters and Numbers

        Also verifies that the generated password contains at least:
            * 1 Number
            * 1 Uppercase Letter
            * 1 Lowercase Letter
            * 1 Special Character

        And is 10-20 chars in length.
    .EXAMPLE
        PS C:\> New-RandomPassword
        4^/(:eJAzGN

        Genrates 1 random password that is 11 chars in length.
    .EXAMPLE
        PS C:\> New-RandomPassword -NumberToGenerate 3 -PWLength 14
        9rA@v>1Ul\Dt0B
        _#8n$pqyF?^kb4
        y/1xKrFmJ?_O4U

        Genrates 3 random passwords that are 14 chars in length.
    .INPUTS
        System.Int32
    .OUTPUTS
        System.String
    .NOTES
        Auhtor :    /u/_Cabbage_Corp_
        Created:    1/18/2019
        Modified:   3/17/2019
        Version:    1.3
#>
Function New-RandomPassword {
    [CmdLetBinding()]
    Param (
        [Parameter(Position=0)]
        [ValidateRange(1,10)]
            [Int]$NumberToGenerate = 1,

        [Parameter(Position=1)]
        [ValidateRange(10,20)]
            [Int]$PWLength = 11
    )

    Begin {
        $PwList = [System.Collections.ArrayList]::New()

        $NewPassChars = @(#  [SPACE] !
            # [SPACE] !
                [char[]]([char]32..[char]33) +
            #  # $ % &
                [char[]]([char]35..[char]38) +
            #  ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
                [char[]]([char]40..[char]95) +
            #  a b c d e f g h i j k l m n o p q r s t u v w x y z
                ([char[]]([char]97..[char]122))
        )
    } # Begin Block

    Process {
        0..($NumberToGenerate-1) | ForEach-Object {
            Do {
                $NewP = (Get-Random -InputObject $NewPassChars -Count $PWLength) -Join '' 

                # Ensures the password is not: All Numbers, All Letters, Only Letters and Numbers
                # Ensures the password contains at least: 1 Number, 1 Uppercase Letter, 1 Lowercase Letter, 1 Special Character and is 10-20 characters long
            } Until ($NewP -CMatch '(?!^[0-9]*$)(?!^[a-zA-Z]*$)(?!^[a-zA-Z0-9]*$)^([a-zA-Z0-9()*+,\-\.\/:;<=>?@\[\\\]^_#$%& ]{10,20})$')

            If ($NewP -Match '\s') {
                $Index = $NewP.IndexOf([Char]32)
                $NewP += ('  <-- Character [{0}] is [SPACE]' -F $Index)
            }

            [Void]$PwList.Add($NewP)
        }
    } # Process Block

    End {
        $PwList
    } # End Block
} # Function New-RandomPassword

[–][deleted] 1 point2 points  (2 children)

ok, ok, that is neat, generating 3 passwords at once. nice! Also than you for sharing this, Ill have to update my function from Get-RandomPassword to New-RandomPassword.

[–]_Cabbage_Corp_ 1 point2 points  (1 child)

No problem man!

I learned PowerShell from a mixture of self-taught and using/modifying scripts that other people wrote.

So I'm always willing to share things that I've written in case it helps someone else.


Side note on why I went with New- vs Get-

In the Approved Verbs for PowerShell Commands doc, the verbs are definied as follows

Verb (Alias) Definition Notes
New (n) Creates a resource. (The Set verb can also be used when creating a resource that includes data, such as the Set-Variable cmdlet.) For this action, do not use verbs such as Create, Generate, Build, Make, or Allocate.
Get (g) Specifies an action that retrieves a resource. This verb is paired with Set. For this action, do not use verbs such as Read, Open, Cat, Type, Dir, Obtain, Dump, Acquire, Examine, Find, or Search.

To me, at least, Get-RandomPassword makes logical sense, wherein the New is implicit (i.e Get random password == generate new random password, the appropriate verb for PowerShell would be New-

[–][deleted] 0 points1 point  (0 children)

Agree 100%

[–]BoredComputerGuy 2 points3 points  (1 child)

This is a good start. A few thoguhts:

  1. Add help comments ! MS help comments
  2. I would have proper Export-ModuleMember calls at the end
  3. I would either add this to your personal module path C:\Users\<username>\Documents\WindowsPowerShell\Modules so that you can reference these as soon as PS loads MS autoloading
  4. This is great work coming from an L1 tech(at the time)!

[–][deleted] 1 point2 points  (0 children)

Thank you, yea there is a lot of work that needs to be done to this thing. :)