my %application = ( 'CI10335478' => { name => 'app_name1', IP => [ 'MemberIP 1', 'MemberIP 2', 'MemberIP 6', ], }, 'CI10334984' => { name => 'app_name2', IP => [ 'MemberIP 4', 'MemberIP 2', ], }, ); #### our %arx_data = (); Need code to build HOH here... Something like this. if ( $data[$class_pos] eq "cmdb_ci_appl" ) { my @ci_record = { description => $data[$ci_pos], name => $data[$name_pos] }; push @{arx_data{ $data[$application_pos] }}, @ci_record; print Dumper( %arx_data ) ; } if ( $data[$application_pos] ne "" && $data[$ip_address_pos] ne "" ) { my @member = { description => $data[$ci_pos], name => $data[$name_pos] }; $arx_data{ $data[$application_pos] }{ 'members' } = $data[$ip_address_pos]; print Dumper( %arx_data ) ; #### #!/usr/bin/perl use strict; use warnings; use 5.014; use MIME::Base64; use Data::Dumper; use utf8; use Text::Unidecode; use XML::Twig; use REST::Client; use Data::Validate::Domain qw(is_hostname); use Socket; use Net::DNS; use Net::MAC; # Just in case we want to request JSON instead of XML from CMDB #use JSON; Just in case we want to request JSON instead of XML from CMDB my $scriptversion = "1.01 (Vance Turner, Staples Inc., 1/20/2016)"; our $header_count = 0; our $fqdn_pos = 0; our $ip_address_pos = 0; our $dns_domain_pos = 0; our $name_pos = 0; our $mac_address_pos = 0; our $application_pos = 0; our $ci_pos = 0; our $class_pos = 0; our @arx_data = (); our $arx_data_ref = \@arx_data; # declare our command line options variables. our $host = 'https://staplessb.service-now.com'; our $wanthelp = 0; our $record_limit = 10; our $class = ''; our $user = ''; our $pwd = ''; our $outputfile = ''; our $forcefile = 0; our $verbosity = 1; sub usage { my $err = shift and select STDERR; print <] [-c ] [-q ] [-w ] [-d ] [-F] [-f] [-D ] [-u] [-v ] [-o ] -t use for the CMDB connection to open. (https://staplessb.service-now.com) -r use as the maximum nomber of CMDB records to retrieve, default = '100' -c use as the CMDB class records you want to retrieve. -u CMDB username to use -p CMDB password to use -v verbosity, default = $verbosity, maximum = 4, written to stderr. -o write output to file named , defaults to stdout if no outputfile is specified -f force usage of if it already exists (unlink before use) Examples: perl $0 -u user -p password -r max_records -o outputfile.csv (creates outputfile.csv) perl $0 -u user -p password -v 4 -r max_records outputfile.csv (creates outputfile.csv, shows progress msgs) EOU exit $err; } # usage use Getopt::Long qw(:config bundling nopermute passthrough); GetOptions ( "help|h|?" => \$wanthelp , "t=s" => \$host, "r=i" => \$record_limit, "c=s" => \$class, "u=s" => \$user, "p=s" => \$pwd, "o=s" => \$outputfile, "f" => \$forcefile, "v:1" => \$verbosity, ); if ($wanthelp) { usage(1); } if ($verbosity > 1) { print STDERR "\$0 script version " . $scriptversion . "\n\n"; } if ($verbosity > 1) { print STDERR "Output file is " . $outputfile . "\n"; } -s $outputfile && $forcefile and unlink $outputfile; if (-s $outputfile) { print STDERR "File '$outputfile' already exists. Overwrite? [y/N] > N\b"; scalar =~ m/^[yj](es|a)?$/i or exit; } my $client = REST::Client->new(host => $host); my $encoded_auth = encode_base64("$user:$pwd", ''); $client->GET("/api/now/table/cmdb_ci?sysparm_limit=$record_limit", {'Authorization' => "Basic $encoded_auth", 'Accept' => 'application/xml'}); my $input_xml = $client->responseContent(); my $field= $ARGV[0] || 'u_ci_id'; my $twig = 'XML::Twig'->new; $twig->xparse($input_xml); my $root = $twig->root; my @records = $root->children; my @sorted = sort { $b->first_child( $field)->text cmp $a->first_child( $field)->text } @records; if ($outputfile ne "") { open my $outputfile_fh, '>:encoding(utf8)', $outputfile or die "Cannot open: $outputfile: $!"; close($outputfile_fh) || warn "close failed: $!"; } my $header_printed = 0; #for my $record (@sorted) { for my $record (@records) { my @info_tags = $record->children; my @data; for my $info_tag (@info_tags) { my $extract = $header_printed ? 'text' : 'name'; if ( $header_printed != 1) { if ( $info_tag->$extract eq 'fqdn' ) { $fqdn_pos = $header_count; } if ( $info_tag->$extract eq 'ip_address' ) { $ip_address_pos = $header_count; } if ( $info_tag->$extract eq 'dns_domain' ) { $dns_domain_pos = $header_count; } if ( $info_tag->$extract eq 'name' ) { $name_pos = $header_count; } if ( $info_tag->$extract eq 'mac_address' ) { $mac_address_pos = $header_count; } if ( $info_tag->$extract eq 'u_application_id' ) { $application_pos = $header_count; } if ( $info_tag->$extract eq 'u_ci_id' ) { $ci_pos = $header_count; } if ( $info_tag->$extract eq 'sys_class_name' ) { $class_pos = $header_count; } } my $work = $info_tag->$extract; $work =~ s/\r|\n//g; # Cleanup Carraige Returns $work =~ s/, / /g; # Cleanup Comma Space $work =~ s/,/ /g; # Cleanup Comma $work =~ s/"//g; # Cleanup Parentheses $work =~ s/^\s+|\s+$//g; # Trim spaces $work =~ s/([^[:ascii:]]+)/unidecode($1)/ge; push @data, $work; $header_count++; } if ( $header_printed == 1) { # if ( $data[$ip_address_pos] eq "" && $data[$name_pos] ne "" && is_hostname($data[$name_pos])) { # my $address = inet_aton($data[$name_pos]) || "Error: Can't resolve."; # if ( $address ne "" && $address ne "Error: Can't resolve." ) { # $address = inet_ntoa($address); # splice @data, ($ip_address_pos), 1, $address; # my $cmdb_name = $data[$name_pos]; # my $cmdb_lc_name = lc $cmdb_name; # splice @data, ($name_pos), 1, $cmdb_lc_name; # } # } # if ( $data[$fqdn_pos] eq "" && $data[$ip_address_pos] ne "" ) { # my $ip_addr = inet_aton($data[$ip_address_pos]) || "Error: Can't resolve."; # if ( $ip_addr ne "" && $ip_addr ne "Error: Can't resolve." ) { # my $hostname = gethostbyaddr($ip_addr, AF_INET ) || "Error: Can't resolve."; # if ( $hostname ne "" && $hostname ne "Error: Can't resolve." ) { # my $lc_hostname = lc $hostname; # splice @data, ($fqdn_pos), 1, $lc_hostname; # my $cmdb_name = $data[$name_pos]; # my $cmdb_lc_name = lc $cmdb_name; # splice @data, ($name_pos), 1, $cmdb_lc_name; # } # } # } # if ( $data[$mac_address_pos] ne "" ) { # my $mac = uc $data[$mac_address_pos]; # $mac =~ s/\'//g; # $mac =~ s/\-//g; # $mac =~ s/\://g; # $mac =~ s/\"//g; # splice @data, ($mac_address_pos), 1, $mac; # } # if ( $data[$dns_domain_pos] eq "" && $data[$fqdn_pos] ne "" ) { # my $dns_domain = $data[$fqdn_pos]; # $dns_domain =~ s/.*?\.//; # splice @data, ($dns_domain_pos), 1, $dns_domain; # } if ( $data[$class_pos] eq "cmdb_ci_appl" ) { my @ci_record = { description => $data[$ci_pos], name => $data[$name_pos] }; push(@$arx_data_ref, @ci_record); print Dumper( @$arx_data_ref ) ; } if ( $data[$application_pos] ne "" && $data[$ip_address_pos] ne "" ) { my @member = { member => $data[$ip_address_pos] }; push(@$arx_data_ref, @member); print Dumper( @$arx_data_ref ) ; } } if ($outputfile ne "") { open my $outputfile_fh, '>>:encoding(utf8)', $outputfile or die "Cannot open: $outputfile: $!"; say $outputfile_fh join ',', map qq("$_"), @data; close($outputfile_fh) || warn "close failed: $!"; } else { say join ',', map qq("$_"), @data; } $header_printed = 1; $header_count = 0; } #### false ';